Skip to content

Instantly share code, notes, and snippets.

@brlafreniere
Last active June 14, 2020 23:52
Show Gist options
  • Save brlafreniere/687332297ab26c078503cf6c39ce9aca to your computer and use it in GitHub Desktop.
Save brlafreniere/687332297ab26c078503cf6c39ce9aca to your computer and use it in GitHub Desktop.
import React from 'react';
import './App.css';
import { BrowserRouter } from "react-router-dom"
import AppContext from "./AppContext"
import IssueBrowser from "./components/IssueBrowser"
import ErrorMessages from "./components/ErrorMessages"
import LoaderWidget from "./components/LoaderWidget"
class App extends React.Component {
// For errors in the format of:
// [{message: "first_name missing..."}, {message: "Email address in use..."}]
setErrorMessages = (errorMessages) => {
this.setState({errorMessages}) }
// Other messages not in the format above. Can set "alert-warning" or
// "alert-success" type messages.
setStatusMessage = (statusType, statusMessage) => {
this.setState({statusType, statusMessage}) }
clearAllMessages = () => {
this.setState({errorMessages: [], statusType: null, statusMessage: null}) }
setAuthToken = () => {}
setLoaded = (val) => { this.setState({loaded: val}) }
state = {
user: {},
loaded: false,
errorMessages: [],
statusType: null,
statusMessage: null,
setErrorMessages: this.setErrorMessages,
clearAllMessages: this.clearAllMessages,
setStatusMessage: this.setStatusMessage,
setLoading: this.setLoading,
setLoaded: this.setLoaded,
setAuthToken: this.setAuthToken,
}
// componentDidMount() {
// this.setState({loading: false})
// }
componentDidUpdate(prevProps, prevState, snapshot) {
if (prevState.errorMessages.length > 0) {
this.setState({errorMessages: []})
}
if (prevState.statusType !== null) {
this.setState({errorMessages: null})
}
if (prevState.statusMessage !== null) {
this.setState({statusMessage: null})
}
}
render() {
return (
<div className="App container">
<React.StrictMode>
<AppContext.Provider value={this.state}>
<BrowserRouter>
{this.state.statusMessage ?
<div className={"alert alert-" + this.state.statusType}>{this.state.statusMessage}</div> : null}
<ErrorMessages errorMessages={this.state.errorMessages} />
{!this.state.loaded ? <LoaderWidget /> : null }
<IssueBrowser />
</BrowserRouter>
</AppContext.Provider>
</React.StrictMode>
</div>
);
}
}
export default App
import React from "react";
import Issues from "../modules/issues";
import {
Switch,
Route,
NavLink,
Link,
useParams,
useHistory
} from "react-router-dom";
import "./IssueBrowser.css";
import UserRegistration from "./UserRegistration"
import AppContext from "../AppContext"
export default function IssueBrowserWithHistory(props) {
let history = useHistory()
return (<IssueBrowser history={history} />)
}
class IssueBrowser extends React.Component {
static contextType = AppContext
state = {
issues: [],
noResponse: false,
loaded: false,
}
render() {
const NewIssueForm = (props) => {
return (
<form onSubmit={this.createIssue}>
<div className="form-group">
<label htmlFor="title">Title</label>
<input className="form-control" name="title" type="text" />
</div>
<div className="form-group">
<label htmlFor="body">Body</label>
<textarea name="body" className="form-control" rows="10"></textarea>
</div>
<input type="submit" className="btn btn-primary" />
</form>
)
}
const IssueDetail = (props) => {
let {id} = useParams()
let issue = this.state.issues.find(issue => issue.id === id)
if (issue) {
return (
<div>
<h1 className="card-title">{issue.title}</h1>
<p className="card-text">{issue.body}</p>
<button className="btn btn-primary" onClick={(e) => this.deleteIssue(issue.id)}>Delete</button>
</div>
)
} else {
return null
}
}
const IssueListItem = (props) => {
return (
<li className="list-group-item" key={props.issue.id}>
<Link to={"/issues/" + props.issue.id}>{props.issue.title}</Link>
</li>
)
}
const IssueList = (props) => {
if (this.state.issues.length > 0) {
return (
<ul className="list-group list-group-flush">
{this.state.issues.map(issue => <IssueListItem key={issue.id} issue={issue} />)}
</ul>
)
} else if (!this.state.noResponse) {
return (
<div>
There are no issues. Aren't you lucky?
</div>
)
}
return null;
}
const MainSwitch = (props) => {
return (
<Switch>
<Route exact path="/users/registration">
<UserRegistration />
</Route>
<Route exact path="/issues/create/">
<NewIssueForm />
</Route>
<Route exact path="/issues/:id">
<IssueDetail />
</Route>
<Route exact path="/">
<IssueList />
</Route>
</Switch>
)
}
return (
<div className="mt-5">
<this.Navigation />
<this.NoResponseFromServer noResponse={this.state.noResponse} />
<div className="p-3 border border-top-0 rounded-bottom">
<MainSwitch />
</div>
</div>
)
}
deleteIssue = (issue_id) => {
this.context.setLoaded(false)
Issues.delete(issue_id)
.then(response => {
this.refreshIssues()
this.props.history.push('/')
})
}
createIssue = (event) => {
event.preventDefault()
this.context.setLoaded(false)
let payload = {
title: event.target.title.value,
body: event.target.body.value }
Issues.create(payload)
.then(response => {
this.refreshIssues()
this.props.history.push('/')
})
.catch(error => { console.log(error) })
}
refreshIssues = () => {
Issues.getAll()
.then(issues => {
this.setState({issues})
this.context.setLoaded(true)
})
.catch(error => {
if (!error.response) {
this.setState({noResponse: true})
}
this.context.setLoaded(true)
})
}
componentDidMount() {
this.refreshIssues()
}
NoResponseFromServer = (props) => {
if (this.state.noResponse) {
return (
<div className="alert alert-danger">
No response received from server. Is it running?
</div>
)
} else {
return null;
}
}
Navigation = (props) => {
return (
<nav className="nav nav-tabs">
<li className="nav-item"><NavLink to="/" exact={true} className="nav-link" activeClassName="active">All</NavLink></li>
<li className="nav-item"><NavLink to="/issues/create/" className="nav-link" activeClassName="active">New</NavLink></li>
<li className="nav-item"><NavLink to="/users/registration/" className="nav-link" activeClassName="active">Register</NavLink></li>
</nav>
)
}
}
import React from "react"
import { Redirect, useHistory } from "react-router-dom"
import Users from "../modules/user"
import AppContext from "../AppContext"
export default function UserRegistrationWithHistory(props) {
let history = useHistory();
return (<UserRegistration history={history} />)
}
class UserRegistration extends React.Component {
static contextType = AppContext
registerUser = (event) => {
event.preventDefault()
this.context.setLoaded(false)
// TODO: check if password matches confirmation, display error message
// if it doesn't
let payload = {
first_name: event.target.first_name.value,
last_name: event.target.last_name.value,
email_address: event.target.email_address.value,
password: event.target.password.value }
Users.create(payload)
.then(response => {
this.context.setStatusMessage("success", "User successfully registered.")
this.context.setLoaded(true)
})
.catch(error => {
if (error.response.data.messages) { this.context.setErrorMessages(error.response.data.messages) }
this.context.setLoaded(true)
})
this.setState({redirect: true})
}
componentWillUnmount() {
this.context.clearAllMessages()
}
render() {
return (
<form onSubmit={this.registerUser}>
<div className="form-group">
<label htmlFor="first_name">First Name:</label>
<input name="first_name" type="text" className="form-control" />
</div>
<div className="form-group">
<label htmlFor="last_name">Last Name:</label>
<input name="last_name" type="text" className="form-control" />
</div>
<div className="form-group">
<label htmlFor="email_address">Email Address:</label>
<input name="email_address" type="text" className="form-control" />
</div>
<div className="form-group">
<label htmlFor="password">Password:</label>
<input name="password" type="password" className="form-control" />
</div>
<div className="form-group">
<label htmlFor="password">Confirm Password:</label>
<input name="password" type="password" className="form-control" />
</div>
<div className="form-group">
<input className="btn btn-primary form-control" type="submit" value="Register" />
</div>
</form>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment