Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Final Project Starter

A starter repository for the Final Project.

Hi, my name is Steven Fiero and this is the repo for my final project for the ACA Advanced class.
3 changes: 2 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
},
"proxy": "http://localhost:3001"
}
110 changes: 108 additions & 2 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,119 @@
import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import axios from 'axios';
import './App.css';
import SignUpSignIn from './SignUpSignIn';
import TopNavbar from './TopNavbar';
import Secret from './Secret';
import axios from 'axios';


class App extends Component {
constructor() {
super();

this.state = {
signUpSignInError: '',
authenticated: localStorage.getItem('token')
};
}


handleSignUp(credentials) {
// Handler is responsible for taking the credentials, verifying the information
// and submitting the request to the API to signup a new user.
const { username, password, confirmPassword } = credentials;
if (!username.trim() || !password.trim() || password.trim() !== confirmPassword.trim()) {
this.setState({
signUpSignInError: 'Must Provide All Fields'
});
} else {
axios.post('/api/signup', credentials)
.then(resp => {
const { token } = resp.data;
localStorage.setItem('token', token);

this.setState({
signUpSignInError: '',
authenticated: token
});
});
}
}


handleSignIn(credentials) {
// Handler is responsible for taking the credentials, verifying the information
// and submitting the request to the API to signin an existing user.
const { username, password } = credentials;
if (!username.trim() || !password.trim()) {
this.setState({
signUpSignInError: 'Must Provide All Fields'
});
} else {
axios.post('/api/signin', credentials)
.then(resp => {
const { token } = resp.data;
localStorage.setItem('token', token);

this.setState({
signUpSignInError: '',
authenticated: token
});
});
}
}


handleSignOut() {
localStorage.removeItem('token');
this.setState({
authenticated: false
});
}


renderSignUpSignIn() {
return <SignUpSignIn
error={this.state.signUpSignInError}
onSignUp={this.handleSignUp.bind(this)}
onSignIn={this.handleSignIn.bind(this)}
/>;
}


renderApp() {
// Returning routing logic to be rendered
// When user successfully signsup / signsin, the token is updated in state,
// which causes a re-render and then the renderApp method is called,
// which allows the user access to the application.
return (
<div>
<Switch>
<Route exact path="/" render={() => <h1>I am protected!</h1>} />
<Route exact path="/secret" component={Secret} />
<Route render={() => <h1>NOT FOUND!</h1>} />
</Switch>
</div>
);
}


// Looking into state for authenticated value to be set, if so render App.
// If state does not have authenticated value, render SignUpSignIn.
render() {
return (
<BrowserRouter>
<div className="App">
<TopNavbar
showNavItems={this.state.authenticated}
onSignOut={this.handleSignOut.bind(this)}
/>
{this.state.authenticated ? this.renderApp() : this.renderSignUpSignIn()}
</div>
</BrowserRouter>
);
}
}


export default App;
7 changes: 6 additions & 1 deletion client/src/Secret.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Component } from 'react';
import axios from 'axios';


class Secret extends Component {
constructor() {
super();
Expand All @@ -10,26 +11,30 @@ class Secret extends Component {
};
}


componentDidMount() {
axios.get('/api/secret', {
// Passing token via authorization header
headers: {
authorization: localStorage.getItem('token')
}
})
.then(resp => {
this.setState({
...this.state,
message: resp.data
});
})
/* eslint no-console: 0 */
.catch(err => console.log(err));
}


render() {
return (
<h1>{this.state.message}</h1>
);
}
}


export default Secret;
75 changes: 75 additions & 0 deletions client/src/SignIn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React, { Component, PropTypes } from 'react';
import { FormGroup, ControlLabel, FormControl, Button } from 'react-bootstrap';


class SignIn extends Component {
constructor() {
super();

this.state = {
username: '',
password: '',
};
}


handleSubmit(event) {
// handleSubmit method is invoked when the form is submitted
event.preventDefault();

this.props.onSignIn({
username: this.state.username,
password: this.state.password
});
}


handleChange(event) {
const { name, value } = event.target;

this.setState({
[name]: value
});
}


render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
<FormGroup>
<ControlLabel>Username</ControlLabel>
<FormControl
type="email"
name="username"
onChange={event => this.handleChange(event)}
placeholder="Enter Username"
value={this.state.username}
/>
</FormGroup>

<FormGroup>
<ControlLabel>Password</ControlLabel>
<FormControl
type="password"
name="password"
onChange={event => this.handleChange(event)}
placeholder="Enter Password"
value={this.state.password}
/>
</FormGroup>

<Button type="submit">
Sign In
</Button>
</form>
);
}
}


SignIn.propTypes = {
onSignIn: PropTypes.func.isRequired
};


export default SignIn;
18 changes: 12 additions & 6 deletions client/src/SignUp.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import React, { Component, PropTypes } from 'react';
import { FormGroup, ControlLabel, FormControl, Button } from 'react-bootstrap';


class SignUp extends Component {
constructor() {
super();

this.state = {
username: '',
password: '',
confirmPassword: '',
}
confirmPassword: ''
};
}


handleSubmit(event) {
// handleSubmit method is invoked when the form is submitted
event.preventDefault();

this.props.onSignUp({
Expand All @@ -22,15 +25,16 @@ class SignUp extends Component {
});
}


handleChange(event) {
const { name, value } = event.target;

this.setState(prev => ({
...prev,
this.setState({
[name]: value
}));
});
}


render() {
return (
<form onSubmit={this.handleSubmit.bind(this)}>
Expand Down Expand Up @@ -69,14 +73,16 @@ class SignUp extends Component {

<Button type="submit">
Sign Up
</Button>
</Button>
</form>
);
}
}


SignUp.propTypes = {
onSignUp: PropTypes.func.isRequired
};


export default SignUp;
11 changes: 8 additions & 3 deletions client/src/SignUpSignIn.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { Component, PropTypes } from 'react';
import { Tabs, Tab, Row, Col, Alert } from 'react-bootstrap';
import SignUp from './SignUp';
import SignIn from './SignIn';


class SignUpSignIn extends Component {

Expand All @@ -22,18 +24,21 @@ class SignUpSignIn extends Component {
<SignUp onSignUp={this.props.onSignUp}/>
</Tab>
<Tab eventKey={2} title="Sign In">
Sign In
<SignIn onSignIn={this.props.onSignIn}/>
</Tab>
</Tabs>
</Col>
</Row>
)
);
}
}


SignUpSignIn.propTypes = {
error: PropTypes.string,
onSignUp: PropTypes.func.isRequired
onSignUp: PropTypes.func.isRequired,
onSignIn: PropTypes.func.isRequired
};


export default SignUpSignIn;
12 changes: 7 additions & 5 deletions client/src/TopNavbar.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { PropTypes } from 'react';
import { Navbar, Nav, NavItem } from 'react-bootstrap';
import { Link } from 'react-router';
import { Link } from 'react-router-dom';


const TopNavbar = (props) => {
return (
Expand All @@ -20,16 +21,17 @@ const TopNavbar = (props) => {
<Nav pullRight>
<Link to="/secret"><Navbar.Text>Secret</Navbar.Text></Link>
</Nav>
</Navbar.Collapse>
: null
</Navbar.Collapse> : null
}
</Navbar>
);
}
};


TopNavbar.propTypes = {
onSignOut: PropTypes.func.isRequired,
showNavItems: PropTypes.bool.isRequired
showNavItems: PropTypes.string.isRequired
};


export default TopNavbar;
Loading