Skip to content

Instantly share code, notes, and snippets.

@jwalt39
Created September 12, 2020 20:22
Show Gist options
  • Save jwalt39/6a3ef45ec7b9d7624946b09f50bca94f to your computer and use it in GitHub Desktop.
Save jwalt39/6a3ef45ec7b9d7624946b09f50bca94f to your computer and use it in GitHub Desktop.
import React, { Component } from "react";
import { render } from "react-dom";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect,
withRouter,
} from "react-router-dom";
import { Login } from "./Authentication";
import AuthenticatedRoute from "./AuthenticatedRoute";
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>
);
}
export default withRouter(App);
import Cookies from "js-cookie";
import React, { Component } from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect,
useHistory,
withRouter,
} 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) {
this.props.history.push("/login");
return false;
}
}
this.props.history.push("/login");
return false;
};
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 default withRouter(AuthenticatedRoute);
import Cookies from "js-cookie";
import React, { Component } from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect,
useHistory,
} from "react-router-dom";
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>
);
}
}
import React, { Component } from "react";
import { BrowserRouter } from "react-router-dom";
import { render } from "react-dom";
import App from "./Components/App";
render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("app")
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment