Created
September 12, 2020 19:49
-
-
Save jwalt39/c64b481c6b9227f1f273ea40424e026f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from "react"; | |
import { render } from "react-dom"; | |
import { | |
BrowserRouter as Router, | |
Switch, | |
Route, | |
Link, | |
Redirect, | |
} from "react-router-dom"; | |
import { AuthenticatedRoute, Login } from "./Authentication"; | |
export class App extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
data: [], | |
loaded: false, | |
placeholder: "Loading", | |
}; | |
} | |
componentDidMount() { | |
fetch("api/characters") | |
.then((response) => { | |
if (response.status > 400) { | |
return this.setState(() => { | |
return { placeholder: "Something went wrong!" }; | |
}); | |
} | |
return response.json(); | |
}) | |
.then((data) => { | |
this.setState(() => { | |
return { | |
data, | |
loaded: true, | |
}; | |
}); | |
}); | |
} | |
render() { | |
return ( | |
<Router> | |
<div> | |
<nav> | |
<ul> | |
<li> | |
<Link to="/">Home</Link> | |
</li> | |
<li> | |
<Link to="/about">About</Link> | |
</li> | |
<li> | |
<Link to="/users">Users</Link> | |
</li> | |
</ul> | |
</nav> | |
{/* A <Switch> looks through its children <Route>s and | |
renders the first one that matches the current URL. */} | |
<Switch> | |
<AuthenticatedRoute path="/about"> | |
<About /> | |
</AuthenticatedRoute> | |
<AuthenticatedRoute path="/users"> | |
<Users /> | |
</AuthenticatedRoute> | |
<Route path="/login"> | |
<Login /> | |
</Route> | |
<Route path="/"> | |
<Home /> | |
</Route> | |
</Switch> | |
</div> | |
</Router> | |
); | |
} | |
} | |
class CharacterList extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
data: [], | |
loaded: false, | |
placeholder: "Loading", | |
}; | |
} | |
componentDidMount() { | |
fetch("api/characters") | |
.then((response) => { | |
if (response.status > 400) { | |
return this.setState(() => { | |
return { placeholder: "Something went wrong!" }; | |
}); | |
} | |
return response.json(); | |
}) | |
.then((data) => { | |
this.setState(() => { | |
return { | |
data, | |
loaded: true, | |
}; | |
}); | |
}); | |
} | |
render() { | |
return ( | |
<ul> | |
{this.state.data.map((character) => { | |
return ( | |
<li key={character.char_name}> | |
<h2>{character.char_name}</h2> | |
<h3>{character.char_race}</h3> | |
</li> | |
); | |
})} | |
</ul> | |
); | |
} | |
} | |
class CreateAccount extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
userName: "", | |
password: "", | |
confirmPassword: "", | |
passwordErrorMessage: "", | |
redirect: false, | |
}; | |
this.handleUserNameChange = this.handleUserNameChange.bind(this); | |
this.handlePasswordChange = this.handlePasswordChange.bind(this); | |
this.handleConfirmPasswordChange = this.handleConfirmPasswordChange.bind( | |
this | |
); | |
this.handleSubmit = this.handleSubmit.bind(this); | |
} | |
handleUserNameChange(event) { | |
this.setState({ userName: event.target.value }); | |
} | |
handlePasswordChange(event) { | |
this.setState({ password: event.target.value }); | |
} | |
handleConfirmPasswordChange(event) { | |
this.setState({ confirmPassword: event.target.value }); | |
} | |
handleSubmit(event) { | |
if (this.state.password !== this.state.confirmPassword) { | |
this.setState({ | |
passwordErrorMessage: "Provided passwords do not match", | |
password: "", | |
confirmPassword: "", | |
errorMessage: "", | |
}); | |
event.preventDefault(); | |
return; | |
} | |
const requestOptions = { | |
method: "POST", | |
headers: { "Content-Type": "application/json" }, | |
body: JSON.stringify({ | |
username: this.state.userName, | |
password: this.state.password, | |
}), | |
}; | |
fetch("api/users/", requestOptions) | |
.then((response) => { | |
console.log(requestOptions.body); | |
// check for error response | |
if (!response.ok) { | |
// get error message from body or default to response status | |
const data = response.json(); | |
const error = (data && data.message) || response.status; | |
return Promise.reject(error); | |
} | |
return response.json(); | |
}) | |
.then((data) => | |
this.setState({ | |
userName: "", | |
password: "", | |
confirmPassword: "", | |
redirect: true, | |
}) | |
) | |
.catch((error) => { | |
this.setState({ passwordErrorMessage: error.toString() }); | |
console.error("There was an error!", error); | |
}); | |
event.preventDefault(); | |
} | |
render() { | |
if (this.state.redirect) { | |
return <Redirect to="/about" />; | |
} | |
return ( | |
<form onSubmit={this.handleSubmit}> | |
<label> | |
Username: | |
<input | |
type="text" | |
value={this.state.userName} | |
onChange={this.handleUserNameChange} | |
/> | |
</label> | |
<p>{this.state.passwordErrorMessage}</p> | |
<label> | |
Password: | |
<input | |
type="text" | |
value={this.state.password} | |
onChange={this.handlePasswordChange} | |
/> | |
</label> | |
<label> | |
Confirm Password: | |
<input | |
type="text" | |
value={this.state.confirmPassword} | |
onChange={this.handleConfirmPasswordChange} | |
/> | |
</label> | |
<input type="submit" value="Submit" /> | |
</form> | |
); | |
} | |
} | |
function About() { | |
return <h2>About</h2>; | |
} | |
function Users() { | |
return <h2>Users</h2>; | |
} | |
function Home() { | |
return ( | |
<div> | |
<h2>Home</h2> | |
<CreateAccount /> | |
</div> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Cookies from "js-cookie"; | |
import React, { Component } from "react"; | |
import { | |
BrowserRouter as Router, | |
Switch, | |
Route, | |
Link, | |
Redirect, | |
useHistory, | |
} from "react-router-dom"; | |
export const getAccessToken = () => Cookies.get("access_token"); | |
export const getRefreshToken = () => Cookies.get("refresh_token"); | |
export const isAuthenticated = () => !!getAccessToken(); | |
function refreshTokens() { | |
const requestOptions = { | |
method: "POST", | |
headers: { "Content-Type": "application/json" }, | |
body: JSON.stringify({ | |
refresh: getRefreshToken(), | |
}), | |
}; | |
return fetch("token/refresh/", requestOptions) | |
.then((response) => { | |
console.log(requestOptions.body); | |
return response.json(); | |
}) | |
.then((data) => { | |
return data; | |
}) | |
.catch((error) => { | |
console.error("There was an error!", error); | |
}); | |
} | |
function setTokens(access_token, refresh_token) { | |
const expires = (tokens.expires_in || 60 * 60) * 1000; | |
const inOneHour = new Date(new Date().getTime() + expires); | |
// you will have the exact same setters in your Login page/app too | |
Cookies.set("access_token", tokens.access_token, { expires: inOneHour }); | |
Cookies.set("refresh_token", tokens.refresh_token); | |
} | |
export const authenticate = async () => { | |
if (getRefreshToken()) { | |
try { | |
const tokens = await refreshTokens(); // call an API, returns tokens | |
setTokens(tokes.access_token, getRefreshToken()); | |
return true; | |
} catch (error) { | |
redirectToLogin(); | |
return false; | |
} | |
} | |
redirectToLogin(); | |
return false; | |
}; | |
const redirectToLogin = () => { | |
this.props.history.push("/login"); | |
}; | |
export const AuthenticatedRoute = ({ component: Component, exact, path }) => ( | |
<Route | |
exact={exact} | |
path={path} | |
render={(props) => | |
isAuthenticated() ? ( | |
<Component {...props} /> | |
) : ( | |
<AuthenticateBeforeRender render={() => <Component {...props} />} /> | |
) | |
} | |
/> | |
); | |
export class AuthenticateBeforeRender extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
isAuthenticated: false, | |
}; | |
} | |
componentDidMount() { | |
authenticate().then((isAuthenticated) => { | |
this.setState({ isAuthenticated }); | |
}); | |
} | |
render() { | |
return this.state.isAuthenticated ? this.props.render() : null; | |
} | |
} | |
export class Login extends Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
userName: "", | |
password: "", | |
passwordErrorMessage: "", | |
redirect: false, | |
}; | |
this.handleUserNameChange = this.handleUserNameChange.bind(this); | |
this.handlePasswordChange = this.handlePasswordChange.bind(this); | |
this.handleSubmit = this.handleSubmit.bind(this); | |
} | |
handleUserNameChange(event) { | |
this.setState({ userName: event.target.value }); | |
} | |
handlePasswordChange(event) { | |
this.setState({ password: event.target.value }); | |
} | |
handleSubmit(event) { | |
if (this.state.password !== this.state.confirmPassword) { | |
this.setState({ | |
passwordErrorMessage: "Provided passwords do not match", | |
password: "", | |
errorMessage: "", | |
}); | |
event.preventDefault(); | |
return; | |
} | |
const requestOptions = { | |
method: "POST", | |
headers: { "Content-Type": "application/json" }, | |
body: JSON.stringify({ | |
username: this.state.userName, | |
password: this.state.password, | |
}), | |
}; | |
fetch("token/obtain/", requestOptions) | |
.then((response) => { | |
console.log(requestOptions.body); | |
// check for error response | |
if (!response.ok) { | |
// get error message from body or default to response status | |
const data = response.json(); | |
const error = (data && data.message) || response.status; | |
return Promise.reject(error); | |
} | |
return response.json(); | |
}) | |
.then((data) => { | |
setTokens(data.access, data.refresh); | |
}) | |
.catch((error) => { | |
this.setState({ passwordErrorMessage: error.toString() }); | |
console.error("There was an error!", error); | |
}); | |
event.preventDefault(); | |
} | |
render() { | |
return ( | |
<div> | |
<h1>Login</h1> | |
<form onSubmit={this.handleSubmit}> | |
<label> | |
Username: | |
<input | |
type="text" | |
value={this.state.userName} | |
onChange={this.handleUserNameChange} | |
/> | |
</label> | |
<p>{this.state.passwordErrorMessage}</p> | |
<label> | |
Password: | |
<input | |
type="text" | |
value={this.state.password} | |
onChange={this.handlePasswordChange} | |
/> | |
</label> | |
<input type="submit" value="Submit" /> | |
</form> | |
</div> | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment