Completed Login/Logout/Protected Routes

This commit is contained in:
Alexander Wong
2017-09-03 10:41:10 -06:00
parent 83ddd34c7c
commit 1bf1dad0b9
14 changed files with 342 additions and 54 deletions

View File

@@ -3,7 +3,9 @@ import { Route, Switch } from "react-router-dom";
import Login from "./Auth/Login";
import Register from "./Auth/Register";
import Settings from "./Auth/Settings";
import VerifyEmail from "./Auth/VerifyEmail";
import PrivateRoute from "./Shared/PrivateRoute";
import About from "./Static/About";
import Footer from "./Static/Footer";
import Home from "./Static/Home";
@@ -31,6 +33,7 @@ class App extends Component {
path="/auth/verify-email/:emailKey"
component={VerifyEmail}
/>
<PrivateRoute path="/auth/settings" component={Settings} />
<Route component={NoMatch} />
</Switch>
</div>

View File

@@ -1,16 +1,111 @@
import React, { Component } from "react";
import { Container } from "semantic-ui-react";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import { Container, Form, Header, Message } from "semantic-ui-react";
import {
clearAuthRequestError,
clearAuthRequestSuccess,
setFormEmail,
setFormPassword
} from "../../actions/auth/reducer.actions";
import { sendLoginRequest } from "../../actions/auth/saga.actions";
import Error from "../Shared/Error";
class Login extends Component {
constructor(props) {
super(props);
this.props.dispatch(clearAuthRequestError());
this.props.dispatch(clearAuthRequestSuccess());
}
changeEmail = event => {
this.props.dispatch(setFormEmail(event.target.value));
};
changePassword = event => {
this.props.dispatch(setFormPassword(event.target.value));
};
onSubmitLogin = event => {
event.preventDefault();
const { dispatch, email, password } = this.props;
dispatch(sendLoginRequest({ email, password }));
};
render() {
return <LoginView />;
const {
isSendingAuthRequest,
authRequestError,
authRequestSuccess,
email,
password,
userToken
} = this.props;
if (userToken) return <Redirect to={"/"} />;
return (
<LoginView
isSendingAuthRequest={isSendingAuthRequest}
authRequestError={authRequestError}
authRequestSuccess={authRequestSuccess}
email={email}
password={password}
changeEmail={this.changeEmail}
changePassword={this.changePassword}
onSubmitLogin={this.onSubmitLogin}
/>
);
}
}
const LoginView = () => (
function mapStateToProps(state) {
return { ...state.auth };
}
const LoginView = ({
isSendingAuthRequest,
authRequestError,
authRequestSuccess,
email,
password,
changeEmail,
changePassword,
onSubmitLogin
}) => (
<Container>
<p>Login</p>
<Header>Login</Header>
<Form
loading={isSendingAuthRequest}
onSubmit={onSubmitLogin}
error={!!authRequestError}
success={!!authRequestSuccess}
>
<Form.Field>
<label>Email</label>
<input
placeholder="bob@gmail.com"
type="email"
value={email}
onChange={changeEmail}
/>
</Form.Field>
<Form.Field>
<label>Password</label>
<input
placeholder="••••••••"
type="password"
value={password}
onChange={changePassword}
/>
</Form.Field>
<Error header="Login failed!" error={authRequestError} />
<Message success>
<Message.Header>Login successful!</Message.Header>
<p>Redirecting you now...</p>
</Message>
<Form.Button>Login</Form.Button>
</Form>
</Container>
);
export default Login;
export default connect(mapStateToProps)(Login);

View File

@@ -1,5 +1,6 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import { Container, Form, Header, Message } from "semantic-ui-react";
import {
@@ -50,8 +51,10 @@ class Register extends Component {
authRequestSuccess,
email,
password,
passwordConfirmation
passwordConfirmation,
userToken
} = this.props;
if (userToken) return <Redirect to={"/"} />;
return (
<RegisterView
isSendingAuthRequest={isSendingAuthRequest}

View File

@@ -0,0 +1,22 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import { Container } from "semantic-ui-react";
class Settings extends Component {
render() {
return <SettingsView />;
}
}
function mapStateToProps(state) {
return { ...state.auth };
}
const SettingsView = () => (
<Container>
<h1>Settings</h1>
<p>todo, change password</p>
</Container>
);
export default connect(mapStateToProps)(Settings);

View File

@@ -1,28 +1,61 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { Menu } from "semantic-ui-react";
import { Dropdown, Menu } from "semantic-ui-react";
import { sendLogoutRequest } from "../actions/auth/saga.actions";
class Navbar extends Component {
dispatchLogoutRequest = () => {
this.props.dispatch(sendLogoutRequest());
};
render() {
const { userToken } = this.props;
return (
<Menu>
<Menu.Item as={Link} to="/">
Caremyway
</Menu.Item>
<Menu.Item as={Link} to="/about">
About
</Menu.Item>
<Menu.Menu position="right">
<Menu.Item as={Link} to="/auth/login">
Login
</Menu.Item>
<Menu.Item as={Link} to="/auth/register">
Register
</Menu.Item>
</Menu.Menu>
</Menu>
<NavbarView
isAuthenticated={!!userToken}
dispatchLogoutRequest={this.dispatchLogoutRequest}
/>
);
}
}
export default Navbar;
function mapStateToProps(state) {
return { ...state.auth };
}
const NavbarView = ({ isAuthenticated, dispatchLogoutRequest }) => (
<Menu>
<Menu.Item as={Link} to="/">
Caremyway
</Menu.Item>
<Menu.Item as={Link} to="/about">
About
</Menu.Item>
{!isAuthenticated &&
<Menu.Menu position="right">
<Menu.Item as={Link} to="/auth/login">
Login
</Menu.Item>
<Menu.Item as={Link} to="/auth/register">
Register
</Menu.Item>
</Menu.Menu>}
{!!isAuthenticated &&
<Menu.Menu position="right">
<Dropdown item text="Account">
<Dropdown.Menu>
<Dropdown.Item as={Link} to="/auth/settings">
Settings
</Dropdown.Item>
<Dropdown.Item onClick={dispatchLogoutRequest}>
Logout
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</Menu.Menu>}
</Menu>
);
export default connect(mapStateToProps)(Navbar);

View File

@@ -0,0 +1,29 @@
import PropTypes from "prop-types";
import React from "react";
import { connect } from "react-redux";
import { Redirect, Route } from "react-router-dom";
const propTypes = {
userToken: PropTypes.string,
component: PropTypes.oneOfType([PropTypes.element, PropTypes.func]).isRequired
};
const PrivateRoute = ({ userToken, component, ...rest }) => {
return (
<Route
{...rest}
render={props => {
if (!!userToken) return React.createElement(component, props);
return <Redirect to="/auth/login" />;
}}
/>
);
};
PrivateRoute.propTypes = propTypes;
const mapStateToProps = state => ({
userToken: state.auth.userToken
});
export default connect(mapStateToProps)(PrivateRoute);