colouring-montreal/app/src/frontend/app.tsx

138 lines
4.6 KiB
TypeScript
Raw Normal View History

import React, { Fragment } from 'react';
2018-09-13 15:41:42 -04:00
import { Route, Switch, Link } from 'react-router-dom';
2019-05-27 13:26:29 -04:00
import PropTypes from 'prop-types';
import '../../node_modules/bootstrap/dist/css/bootstrap.min.css';
import './app.css';
import Header from './header';
import AboutPage from './pages/about';
import ContributorAgreementPage from './pages/contributor-agreement';
import PrivacyPolicyPage from './pages/privacy-policy';
import DataExtracts from './pages/data-extracts';
import Login from './user/login';
import MyAccountPage from './user/my-account';
import SignUp from './user/signup';
import ForgottenPassword from './user/forgotten-password';
import PasswordReset from './user/password-reset';
2019-09-08 20:09:05 -04:00
import MapApp from './map-app';
2019-10-02 13:38:12 -04:00
import ContactPage from './pages/contact';
2019-10-02 14:26:18 -04:00
import DataAccuracyPage from './pages/data-accuracy';
2019-09-08 20:09:05 -04:00
interface AppProps {
user?: any;
building?: any;
building_like?: boolean;
}
2019-02-05 16:41:31 -05:00
/**
* App component
*
* This is the top-level stateful frontend component
* - rendered from props, instantiated either server-side in server.js or client-side in
* client.js
* - state (including user, current building) is initialised from props
* - callbacks to update top-level state are passed down to subcomponents
* - render method wraps a react-router switch - this drives which version of the sidebar and
* map or other pages are rendered, based on the URL. Use a react-router-dom <Link /> in
* child components to navigate without a full page reload.
*/
2019-09-08 20:09:05 -04:00
class App extends React.Component<AppProps, any> { // TODO: add proper types
static propTypes = { // TODO: generate propTypes from TS
user: PropTypes.object,
building: PropTypes.object,
building_like: PropTypes.bool
2019-09-08 20:09:05 -04:00
};
2019-09-08 20:09:05 -04:00
constructor(props: Readonly<AppProps>) {
super(props);
2019-09-08 20:09:05 -04:00
2018-09-10 18:34:56 -04:00
this.state = {
2019-09-08 20:09:05 -04:00
user: props.user
2018-09-10 18:34:56 -04:00
};
this.login = this.login.bind(this);
2018-10-20 07:20:10 -04:00
this.updateUser = this.updateUser.bind(this);
this.logout = this.logout.bind(this);
}
login(user) {
2018-09-30 15:28:33 -04:00
if (user.error) {
this.logout();
2019-09-08 20:09:05 -04:00
return;
2018-09-30 15:28:33 -04:00
}
this.setState({user: user});
}
2018-10-20 07:20:10 -04:00
updateUser(user){
this.setState({user: { ...this.state.user, ...user }});
}
2018-09-10 18:34:56 -04:00
logout() {
this.setState({user: undefined});
}
render() {
return (
<Fragment>
<Header user={this.state.user} />
<main>
<Switch>
<Route exact path="/about.html" component={AboutPage} />
<Route exact path="/login.html">
<Login user={this.state.user} login={this.login} />
</Route>
<Route exact path="/forgotten-password.html" component={ForgottenPassword} />
<Route exact path="/password-reset.html" component={PasswordReset} />
<Route exact path="/sign-up.html">
<SignUp user={this.state.user} login={this.login} />
</Route>
<Route exact path="/my-account.html">
<MyAccountPage
user={this.state.user}
updateUser={this.updateUser}
logout={this.logout}
/>
</Route>
<Route exact path="/privacy-policy.html" component={PrivacyPolicyPage} />
<Route exact path="/contributor-agreement.html" component={ContributorAgreementPage} />
2019-10-02 14:26:18 -04:00
<Route exact path="/data-accuracy.html" component={DataAccuracyPage} />
<Route exact path="/data-extracts.html" component={DataExtracts} />
2019-10-02 13:38:12 -04:00
<Route exact path="/contact.html" component={ContactPage} />
<Route exact path={["/", "/:mode(view|edit|multi-edit)/:category/:building(\\d+)?"]} render={(props) => (
2019-09-08 20:09:05 -04:00
<MapApp
{...props}
building={this.props.building}
building_like={this.props.building_like}
user={this.state.user}
/>
)} />
<Route component={NotFound} />
</Switch>
</main>
</Fragment>
);
}
}
2019-02-05 16:41:31 -05:00
/**
* Component to fall back on in case of 404 or no other match
*/
const NotFound = () => (
<article>
<section className="main-col">
2018-10-03 16:46:51 -04:00
<h1 className="h1">Page not found</h1>
2018-09-13 15:41:42 -04:00
<p className="lead">
2019-05-27 11:23:58 -04:00
We can&rsquo;t find that one anywhere.
2018-09-13 15:41:42 -04:00
</p>
<Link className="btn btn-outline-dark" to="/">Back home</Link>
</section>
</article>
);
export default App;