Update router-router to v4.2.0 (#872)
* Migrated to react-router v4.2.0
This commit is contained in:
Родитель
8bf01f885b
Коммит
b12c8a83b7
|
@ -1,9 +1,9 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactGA from 'react-ga';
|
||||
import { browserHistory, Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
import Utility from '../../js/utility.js';
|
||||
import SignOutButton from '../sign-out-button.jsx';
|
||||
|
||||
class Bio extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -55,31 +55,7 @@ class Bio extends React.Component {
|
|||
renderSignOut() {
|
||||
if (!this.props.my_profile) return null;
|
||||
|
||||
return <div className="ml-sm-3"><button className="btn btn-link inline-link" onClick={(event) => this.handleLogOutBtnClick(event)}>Sign out</button></div>;
|
||||
}
|
||||
|
||||
handleSocialMediaClick(event, type) {
|
||||
ReactGA.event({
|
||||
category: `Profile`,
|
||||
action: `Social link tap`,
|
||||
label: `${this.profileOwnerName} - ${type}`,
|
||||
transport: `beacon`
|
||||
});
|
||||
}
|
||||
|
||||
handleLogOutBtnClick(event) {
|
||||
event.preventDefault();
|
||||
|
||||
ReactGA.event({
|
||||
category: `Account`,
|
||||
action: `Logout`,
|
||||
label: `Logout ${window.location.pathname}`,
|
||||
});
|
||||
|
||||
this.props.user.logout();
|
||||
browserHistory.push({
|
||||
pathname: `/featured`
|
||||
});
|
||||
return <div className="ml-sm-3"><SignOutButton user={this.props.user} history={this.props.history} /></div>;
|
||||
}
|
||||
|
||||
renderMeta(type, text, link) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { NavLink as ReactRouterNavLink } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
|
@ -18,7 +18,7 @@ class NavLink extends React.Component {
|
|||
let classes = classNames(`open-sans`, this.props.className);
|
||||
|
||||
return (
|
||||
<Link {...this.props}
|
||||
<ReactRouterNavLink {...this.props}
|
||||
className={classes}
|
||||
activeClassName="active"
|
||||
onClick={() => this.handleClick()}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import React from 'react';
|
||||
import ReactGA from 'react-ga';
|
||||
import { IndexLink } from 'react-router';
|
||||
import { NavLink as ReactRouterNavLink } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
import NavLink from '../nav-link/nav-link.jsx';
|
||||
import user from '../../js/app-user';
|
||||
import utility from '../../js/utility';
|
||||
|
||||
|
||||
class NavListItem extends React.Component {
|
||||
render() {
|
||||
let classes = classNames(`d-inline-block my-md-0`, this.props.className, {
|
||||
|
@ -29,7 +30,7 @@ class NavBar extends React.Component {
|
|||
|
||||
componentDidMount() {
|
||||
user.addListener(this);
|
||||
user.verify();
|
||||
user.verify(this.props.location, this.props.history);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -125,10 +126,10 @@ class NavBar extends React.Component {
|
|||
<div className="container">
|
||||
<div className="row open-sans align-items-center">
|
||||
<div className="col-12 col-lg-9 d-flex flex-column flex-lg-row" id="main-nav-wrapper">
|
||||
<IndexLink to="/" className="d-inline-block">
|
||||
<ReactRouterNavLink to="/" className="d-inline-block">
|
||||
<img src="/assets/svg/pulse-logo-mobile.svg" alt="Mozilla Pulse" className="logo hidden-md-up" width="40" />
|
||||
<img src="/assets/svg/pulse-logo.svg" alt="Mozilla Pulse" className="logo hidden-sm-down" width="187" />
|
||||
</IndexLink>
|
||||
</ReactRouterNavLink>
|
||||
{ this.renderNavList() }
|
||||
</div>
|
||||
<div className="pinned col-6 col-lg-3">
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const DEFAULT_TEXT = `Help with this, or find other projects that have similar ways to get involved.`;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import Utility from '../../../js/utility.js';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
class Thumbnail extends React.Component {
|
||||
constructor(props) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
|
||||
class Title extends React.Component {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import ReactGA from 'react-ga';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
|
|
|
@ -14,12 +14,20 @@ class ProjectList extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
pageSettings.setCurrentPathname(window.location.pathname);
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
if (!this.state.inPageUpdate && this.props.restoreScrollPosition) {
|
||||
if (!this.state.inPageUpdate) {
|
||||
pageSettings.restoreScrollPosition();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
pageSettings.setScrollPosition();
|
||||
}
|
||||
|
||||
handleLoadMoreBtnClick() {
|
||||
ReactGA.event({
|
||||
category: `Browse`,
|
||||
|
|
|
@ -156,7 +156,6 @@ class ProjectLoader extends React.Component {
|
|||
loadingData={this.state.loadingData}
|
||||
moreEntriesToFetch={this.state.moreEntriesToFetch}
|
||||
fetchData={() => this.fetchData()}
|
||||
restoreScrollPosition={pageSettings.shouldRestore}
|
||||
onModerationMode={!!this.props.moderationState} />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import React from 'react';
|
||||
import ReactGA from 'react-ga';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
class SignOutButton extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
handleLogOutBtnClick(event) {
|
||||
event.preventDefault();
|
||||
|
||||
ReactGA.event({
|
||||
category: `Account`,
|
||||
action: `Logout`,
|
||||
label: `Logout ${window.location.pathname}`,
|
||||
});
|
||||
|
||||
this.props.user.logout();
|
||||
this.props.history.push({
|
||||
pathname: `/featured`
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<button className="btn btn-link inline-link" onClick={(event) => this.handleLogOutBtnClick(event)}>Sign out</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SignOutButton.propTypes = {
|
||||
user: PropTypes.object.isRequired,
|
||||
history: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default SignOutButton;
|
|
@ -24,7 +24,7 @@ export default {
|
|||
// https://developers.google.com/analytics/devguides/collection/analyticsjs/command-queue-reference#set
|
||||
ReactGA.set({ page: window.location.pathname });
|
||||
// https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#location
|
||||
ReactGA.set({ location: window.location.href });
|
||||
ReactGA.set({ location: window.location.href, title: window.title });
|
||||
|
||||
ReactGA.pageview(`${window.location.pathname}/${window.location.search}`);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ class PageSettings {
|
|||
restoreScrollPosition() {
|
||||
if (typeof window !== `undefined` && this.shouldRestore) {
|
||||
window.scrollTo(0, this.currentScrollPosition);
|
||||
this.shouldRestore = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { browserHistory } from 'react-router';
|
||||
import qs from "qs";
|
||||
import env from "../config/env.generated.json";
|
||||
import localstorage from './localstorage.js';
|
||||
import Service from './service.js';
|
||||
|
@ -21,18 +21,17 @@ const Login = {
|
|||
* setUserData(error, username). If the user is not logged in
|
||||
* the username will be falsey.
|
||||
*/
|
||||
isLoggedIn(location, setUserData) {
|
||||
isLoggedIn(location, history, setUserData) {
|
||||
if (location) {
|
||||
// Make sure that oauth loggedin=True/False query parameters are
|
||||
// removed from the current URL, as they should not end up in
|
||||
// bookmarks etc.
|
||||
const query = location.query;
|
||||
let query = qs.parse(location.search.substring(1));
|
||||
|
||||
if (query.loggedin) {
|
||||
delete location.query.loggedin;
|
||||
browserHistory.replace({
|
||||
pathname: location.pathname,
|
||||
query: query
|
||||
});
|
||||
delete query.loggedin;
|
||||
location.search = `?${qs.stringify(query)}`;
|
||||
history.replace(location);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,8 +119,8 @@ class User {
|
|||
window.location = Login.getLoginURL(redirectUrl);
|
||||
}
|
||||
|
||||
verify(location) {
|
||||
Login.isLoggedIn(location, (error, username, customName, email, moderator) => {
|
||||
verify(location, history) {
|
||||
Login.isLoggedIn(location, history, (error, username, customName, email, moderator) => {
|
||||
this.update(error, username, customName, email, moderator);
|
||||
});
|
||||
}
|
||||
|
|
12
main.jsx
12
main.jsx
|
@ -1,15 +1,13 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Router, browserHistory } from 'react-router';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import Analytics from './js/analytics.js';
|
||||
import routes from './routes.jsx';
|
||||
import App from './routes.jsx';
|
||||
|
||||
Analytics.initialize();
|
||||
|
||||
let routerUpdateHandler = function() {
|
||||
Analytics.logPageView();
|
||||
};
|
||||
|
||||
ReactDOM.render((
|
||||
<Router routes={routes} history={browserHistory} onUpdate={routerUpdateHandler} />
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
), document.getElementById(`app`));
|
||||
|
|
|
@ -4645,13 +4645,14 @@
|
|||
"integrity": "sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys="
|
||||
},
|
||||
"history": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-3.3.0.tgz",
|
||||
"integrity": "sha1-/O3M6PEpdTcVRdc1RhAzV5ptrpw=",
|
||||
"version": "4.7.2",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz",
|
||||
"integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==",
|
||||
"requires": {
|
||||
"invariant": "2.2.2",
|
||||
"loose-envify": "1.3.1",
|
||||
"query-string": "4.3.4",
|
||||
"resolve-pathname": "2.2.0",
|
||||
"value-equal": "0.4.0",
|
||||
"warning": "3.0.0"
|
||||
}
|
||||
},
|
||||
|
@ -4671,9 +4672,9 @@
|
|||
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0="
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz",
|
||||
"integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs="
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz",
|
||||
"integrity": "sha1-ND24TGAYxlB3iJgkATWhQg7iLOA="
|
||||
},
|
||||
"home-or-tmp": {
|
||||
"version": "2.0.0",
|
||||
|
@ -6885,18 +6886,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
|
||||
"integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM="
|
||||
},
|
||||
"query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"requires": {
|
||||
"object-assign": "4.1.1",
|
||||
"strict-uri-encode": "1.1.0"
|
||||
}
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
|
||||
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
|
||||
},
|
||||
"querystring": {
|
||||
"version": "0.2.0",
|
||||
|
@ -7073,16 +7065,44 @@
|
|||
}
|
||||
},
|
||||
"react-router": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-3.2.0.tgz",
|
||||
"integrity": "sha512-sXlLOg0TRCqnjCVskqBHGjzNjcJKUqXEKnDSuxMYJSPJNq9hROE9VsiIW2kfIq7Ev+20Iz0nxayekXyv0XNmsg==",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.2.0.tgz",
|
||||
"integrity": "sha512-DY6pjwRhdARE4TDw7XjxjZsbx9lKmIcyZoZ+SDO7SBJ1KUeWNxT22Kara2AC7u6/c2SYEHlEDLnzBCcNhLE8Vg==",
|
||||
"requires": {
|
||||
"create-react-class": "15.6.2",
|
||||
"history": "3.3.0",
|
||||
"hoist-non-react-statics": "1.2.0",
|
||||
"history": "4.7.2",
|
||||
"hoist-non-react-statics": "2.3.1",
|
||||
"invariant": "2.2.2",
|
||||
"loose-envify": "1.3.1",
|
||||
"path-to-regexp": "1.7.0",
|
||||
"prop-types": "15.6.0",
|
||||
"warning": "3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
|
||||
"integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
|
||||
"requires": {
|
||||
"isarray": "0.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-router-dom": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.2.2.tgz",
|
||||
"integrity": "sha512-cHMFC1ZoLDfEaMFoKTjN7fry/oczMgRt5BKfMAkTu5zEuJvUiPp1J8d0eXSVTnBh6pxlbdqDhozunOOLtmKfPA==",
|
||||
"requires": {
|
||||
"history": "4.7.2",
|
||||
"invariant": "2.2.2",
|
||||
"loose-envify": "1.3.1",
|
||||
"prop-types": "15.6.0",
|
||||
"react-router": "4.2.0",
|
||||
"warning": "3.0.0"
|
||||
}
|
||||
},
|
||||
|
@ -7337,6 +7357,13 @@
|
|||
"tough-cookie": "2.3.2",
|
||||
"tunnel-agent": "0.6.0",
|
||||
"uuid": "3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"qs": {
|
||||
"version": "6.4.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
|
||||
"integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM="
|
||||
}
|
||||
}
|
||||
},
|
||||
"require-directory": {
|
||||
|
@ -7379,6 +7406,11 @@
|
|||
"integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
|
||||
"dev": true
|
||||
},
|
||||
"resolve-pathname": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz",
|
||||
"integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg=="
|
||||
},
|
||||
"restore-cursor": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
|
||||
|
@ -8086,11 +8118,6 @@
|
|||
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
|
||||
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI="
|
||||
},
|
||||
"strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
|
||||
},
|
||||
"string-length": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz",
|
||||
|
@ -9032,6 +9059,11 @@
|
|||
"spdx-expression-parse": "1.0.4"
|
||||
}
|
||||
},
|
||||
"value-equal": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz",
|
||||
"integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw=="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
|
|
@ -86,13 +86,15 @@
|
|||
"npm-run-all": "^4.1.1",
|
||||
"postcss-cli-simple": "^1.0.3",
|
||||
"prop-types": "^15.6.0",
|
||||
"qs": "^6.5.1",
|
||||
"react": "^15.6.2",
|
||||
"react-debounce-input": "^3.1.0",
|
||||
"react-dom": "^15.6.2",
|
||||
"react-formbuilder": "^0.10.0",
|
||||
"react-ga": "^2.3.5",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-router": "^3.2.0",
|
||||
"react-router": "^4.2.0",
|
||||
"react-router-dom": "^4.2.2",
|
||||
"react-select": "^1.0.0-rc.10",
|
||||
"react-tag-autocomplete": "^5.4.1",
|
||||
"shx": "^0.2.1",
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import React from 'react';
|
||||
import ReactGA from 'react-ga';
|
||||
import { browserHistory, Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Helmet } from "react-helmet";
|
||||
import { Form } from 'react-formbuilder';
|
||||
import SignOutButton from '../../components/sign-out-button.jsx';
|
||||
import HintMessage from '../../components/hint-message/hint-message.jsx';
|
||||
import Service from '../../js/service.js';
|
||||
import utility from '../../js/utility';
|
||||
|
@ -43,7 +44,7 @@ class Add extends React.Component {
|
|||
|
||||
componentDidMount() {
|
||||
user.addListener(this);
|
||||
user.verify(this.props.router.location);
|
||||
user.verify(this.props.location, this.props.history);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -70,21 +71,6 @@ class Add extends React.Component {
|
|||
user.login(utility.getCurrentURL());
|
||||
}
|
||||
|
||||
handleLogOutBtnClick(event) {
|
||||
event.preventDefault();
|
||||
|
||||
ReactGA.event({
|
||||
category: `Account`,
|
||||
action: `Logout`,
|
||||
label: `Logout ${window.location.pathname}`,
|
||||
});
|
||||
|
||||
user.logout();
|
||||
browserHistory.push({
|
||||
pathname: `/featured`
|
||||
});
|
||||
}
|
||||
|
||||
handleCreatorClick(event) {
|
||||
event.preventDefault();
|
||||
this.setState({numCreatorFields: this.state.numCreatorFields+1});
|
||||
|
@ -145,14 +131,14 @@ class Add extends React.Component {
|
|||
.get(entryId)
|
||||
.then(result => {
|
||||
if(result) {
|
||||
browserHistory.push({
|
||||
this.props.history.push({
|
||||
pathname: `/entry/${entryId}`,
|
||||
query: {
|
||||
justPostedByUser: true
|
||||
}
|
||||
});
|
||||
} else {
|
||||
browserHistory.push({
|
||||
this.props.history.push({
|
||||
pathname: `/submitted`,
|
||||
query: { entryId }
|
||||
});
|
||||
|
@ -161,7 +147,7 @@ class Add extends React.Component {
|
|||
.catch(reason => {
|
||||
// a 404 is yielded as an error by Service.entry
|
||||
console.error(reason);
|
||||
browserHistory.push({
|
||||
this.props.history.push({
|
||||
pathname: `/submitted`,
|
||||
query: { entryId }
|
||||
});
|
||||
|
@ -196,7 +182,7 @@ class Add extends React.Component {
|
|||
<h2>Basic Info</h2>
|
||||
<div className="posted-by">
|
||||
<p className="d-inline-block mr-3 mb-3">Posted by: <span className="text-muted">{user.name}</span></p>
|
||||
<p className="d-inline-block text-muted">Not you? <button className="btn btn-link inline-link" onClick={(event) => this.handleLogOutBtnClick(event)}>Sign out</button>.</p>
|
||||
<p className="d-inline-block text-muted">Not you? <SignOutButton user={user} history={this.props.history} />.</p>
|
||||
</div>
|
||||
<Form ref="basicForm" fields={basicInfoFields}
|
||||
inlineErrors={true}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import IssuesField from '../../../components/form-fields/issues.jsx';
|
||||
import validator from './validator';
|
||||
import Creators from './creators';
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import { browserHistory, Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import qs from 'qs';
|
||||
import { Helmet } from "react-helmet";
|
||||
import HintMessage from '../../components/hint-message/hint-message.jsx';
|
||||
|
||||
|
@ -14,8 +15,8 @@ export default class Submitted extends React.Component {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
let location = this.props.router.location;
|
||||
let query = location.query;
|
||||
let location = this.props.location;
|
||||
let query = qs.parse(this.props.location.search.substring(1));
|
||||
|
||||
if (query && query.entryId) {
|
||||
let entryId = parseInt(query.entryId, 10);
|
||||
|
@ -28,7 +29,7 @@ export default class Submitted extends React.Component {
|
|||
|
||||
// remove 'entryId' query from URL
|
||||
delete query.entryId;
|
||||
browserHistory.replace({
|
||||
this.props.history.replace({
|
||||
pathname: location.pathname,
|
||||
query: query
|
||||
});
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Helmet } from "react-helmet";
|
||||
import ProjectLoader from '../components/project-loader/project-loader.jsx';
|
||||
import HintMessage from '../components/hint-message/hint-message.jsx';
|
||||
import Service from '../js/service.js';
|
||||
import bookmarkManager from '../js/bookmarks-manager';
|
||||
import user from '../js/app-user';
|
||||
import pageSettings from '../js/app-page-settings';
|
||||
|
||||
class Bookmarks extends React.Component{
|
||||
constructor(props) {
|
||||
|
@ -26,15 +25,10 @@ class Bookmarks extends React.Component{
|
|||
|
||||
componentDidMount() {
|
||||
// get IDs of user's bookmarked entries
|
||||
this.setState({lsBookmarkedIds: bookmarkManager.bookmarks.get()}, () => {
|
||||
if (pageSettings.shouldRestore) {
|
||||
// restore state back to what is stored in pageSettings
|
||||
this.setState(pageSettings.currentList);
|
||||
}
|
||||
});
|
||||
this.setState({lsBookmarkedIds: bookmarkManager.bookmarks.get()});
|
||||
|
||||
user.addListener(this);
|
||||
user.verify(this.props.router.location);
|
||||
user.verify(this.props.location, this.props.history);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -141,9 +135,7 @@ class Bookmarks extends React.Component{
|
|||
}
|
||||
|
||||
Bookmarks.propTypes = {
|
||||
router: PropTypes.shape({
|
||||
location: PropTypes.object
|
||||
}).isRequired
|
||||
location: PropTypes.object
|
||||
};
|
||||
|
||||
export default Bookmarks;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import React from 'react';
|
||||
import { browserHistory } from 'react-router';
|
||||
import { Helmet } from "react-helmet";
|
||||
import qs from 'qs';
|
||||
import LoadingNotice from '../components/loading-notice.jsx';
|
||||
import ProjectCardDetialed from '../components/project-card/project-card-detailed.jsx';
|
||||
import Service from '../js/service.js';
|
||||
import Utility from '../js/utility.js';
|
||||
import pageSettings from '../js/app-page-settings.js';
|
||||
|
||||
const NO_ENTRY_TITLE = `Entry unavailable`;
|
||||
const NO_ENTRY_BLOCK = (
|
||||
|
@ -28,7 +29,11 @@ class Entry extends React.Component {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchData(this.props.params.entryId);
|
||||
this.fetchData(this.props.match.params.entryId);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
pageSettings.setRestore(true);
|
||||
}
|
||||
|
||||
fetchData(entryId = ``) {
|
||||
|
@ -51,8 +56,8 @@ class Entry extends React.Component {
|
|||
}
|
||||
|
||||
checkIfRedirectedFromFormSubmission() {
|
||||
let location = this.props.router.location;
|
||||
let query = location.query;
|
||||
let location = this.props.location;
|
||||
let query = qs.parse(location.search.substring(1));
|
||||
let justPostedByUser;
|
||||
|
||||
if (query && query.justPostedByUser) {
|
||||
|
@ -60,7 +65,7 @@ class Entry extends React.Component {
|
|||
|
||||
// remove 'justPostedByUser' query from URL
|
||||
delete query.justPostedByUser;
|
||||
browserHistory.replace({
|
||||
this.props.history.replace({
|
||||
pathname: location.pathname,
|
||||
query: query
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@ import ProjectLoader from '../components/project-loader/project-loader.jsx';
|
|||
import Utility from '../js/utility.js';
|
||||
|
||||
export default function (props) {
|
||||
const issueName = Utility.getIssueNameFromUriPath(props.params.issue);
|
||||
const issueName = Utility.getIssueNameFromUriPath(props.match.params.issue);
|
||||
|
||||
return <div>
|
||||
<Helmet><title>{issueName}</title></Helmet>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Helmet } from "react-helmet";
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import IssueSelector from '../../components/issue-selector/issue-selector.jsx';
|
||||
import Service from '../../js/service';
|
||||
import Utility from '../../js/utility';
|
||||
|
|
|
@ -13,7 +13,7 @@ class Moderation extends React.Component {
|
|||
|
||||
componentDidMount() {
|
||||
user.addListener(this);
|
||||
user.verify(this.props.router.location);
|
||||
user.verify(this.props.location, this.props.history);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import ReactGA from 'react-ga';
|
||||
import NotFound from './not-found.jsx';
|
||||
import Service from '../js/service';
|
||||
|
@ -20,7 +20,7 @@ class MyProfile extends React.Component {
|
|||
|
||||
componentDidMount() {
|
||||
user.addListener(this);
|
||||
user.verify(this.props.router.location);
|
||||
user.verify(this.props.location, this.props.history);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -32,7 +32,7 @@ class MyProfile extends React.Component {
|
|||
if (event === `verified` ) {
|
||||
this.setState({ user }, () => {
|
||||
if (this.state.user.loggedin) {
|
||||
this.fetchProfile(this.props.params.id, newState => {
|
||||
this.fetchProfile(this.props.match.params.id, newState => {
|
||||
this.setState(newState);
|
||||
});
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ class MyProfile extends React.Component {
|
|||
renderProfile() {
|
||||
if (!this.state.userProfile) return <NotFound header="Profile not found" />;
|
||||
|
||||
return <Profile profile={this.state.userProfile} user={this.state.user} />;
|
||||
return <Profile profile={this.state.userProfile} user={this.state.user} history={this.props.history} />;
|
||||
}
|
||||
|
||||
getContentForLoggedInUser() {
|
||||
|
|
|
@ -1,17 +1,26 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import HintMessage from '../components/hint-message/hint-message.jsx';
|
||||
|
||||
const NotFound = (props) => {
|
||||
return (
|
||||
<HintMessage iconComponent={<img src="/assets/svg/icon-404.svg" />}
|
||||
header={props.header}
|
||||
linkComponent={props.linkComponent}>
|
||||
{ props.children || <p>Check your URL or try a search. Still no luck? <a href="https://github.com/mozilla/network-pulse/issues/new">Let us know</a>.</p> }
|
||||
</HintMessage>
|
||||
);
|
||||
};
|
||||
class NotFound extends React.Component {
|
||||
componentWillMount() {
|
||||
const { staticContext } = this.props;
|
||||
if (staticContext) {
|
||||
staticContext.pageNotFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<HintMessage iconComponent={<img src="/assets/svg/icon-404.svg" />}
|
||||
header={this.props.header}
|
||||
linkComponent={this.props.linkComponent}>
|
||||
{ this.props.children || <p>Check your URL or try a search. Still no luck? <a href="https://github.com/mozilla/network-pulse/issues/new">Let us know</a>.</p> }
|
||||
</HintMessage>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
NotFound.propTypes = {
|
||||
header: PropTypes.string,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import validator from '../../../js/form-validator';
|
||||
import IssuesField from '../../../components/form-fields/issues.jsx';
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { browserHistory, Link } from 'react-router';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Helmet } from "react-helmet";
|
||||
import { Form } from 'react-formbuilder';
|
||||
import NotFound from '../not-found.jsx';
|
||||
|
@ -32,7 +32,7 @@ class ProfileEdit extends React.Component{
|
|||
|
||||
componentDidMount() {
|
||||
user.addListener(this);
|
||||
user.verify(this.props.router.location);
|
||||
user.verify(this.props.location, this.props.history);
|
||||
|
||||
this.loadCurrentProfile();
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ class ProfileEdit extends React.Component{
|
|||
event.preventDefault();
|
||||
|
||||
user.logout();
|
||||
browserHistory.push({
|
||||
this.props.history.push({
|
||||
pathname: `/featured`
|
||||
});
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ class ProfileEdit extends React.Component{
|
|||
Service.myProfile
|
||||
.put(profile)
|
||||
.then(() => {
|
||||
browserHistory.push({
|
||||
this.props.history.push({
|
||||
pathname: `/profile/me`,
|
||||
});
|
||||
})
|
||||
|
@ -203,9 +203,7 @@ class ProfileEdit extends React.Component{
|
|||
}
|
||||
|
||||
ProfileEdit.propTypes = {
|
||||
router: PropTypes.shape({
|
||||
location: PropTypes.object
|
||||
}).isRequired
|
||||
location: PropTypes.object
|
||||
};
|
||||
|
||||
export default ProfileEdit;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Helmet } from "react-helmet";
|
||||
import Bio from '../components/bio/bio.jsx';
|
||||
import ProjectList from '../components/project-list/project-list.jsx';
|
||||
import pageSettings from '../js/app-page-settings';
|
||||
|
||||
class Profile extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -12,7 +12,7 @@ class Profile extends React.Component {
|
|||
renderProfile() {
|
||||
if (!this.props.profile) return null;
|
||||
|
||||
return <div className="col-12"><Bio {...this.props.profile} user={this.props.user} /></div>;
|
||||
return <div className="col-12"><Bio {...this.props.profile} user={this.props.user} history={this.props.history} /></div>;
|
||||
}
|
||||
|
||||
renderProjects(entries, label) {
|
||||
|
@ -30,7 +30,6 @@ class Profile extends React.Component {
|
|||
loadingData={false}
|
||||
moreEntriesToFetch={false}
|
||||
fetchData={()=>{}}
|
||||
restoreScrollPosition={pageSettings.shouldRestore}
|
||||
onModerationMode={false}
|
||||
/>
|
||||
</div>
|
||||
|
@ -51,4 +50,10 @@ class Profile extends React.Component {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
Profile.propTypes = {
|
||||
user: PropTypes.object.isRequired,
|
||||
history: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default Profile;
|
||||
|
|
|
@ -17,9 +17,9 @@ class PublicProfile extends React.Component {
|
|||
|
||||
componentDidMount() {
|
||||
user.addListener(this);
|
||||
user.verify(this.props.router.location);
|
||||
user.verify(this.props.location, this.props.history);
|
||||
|
||||
this.fetchProfile(this.props.params.id, newState => {
|
||||
this.fetchProfile(this.props.match.params.id, newState => {
|
||||
this.setState(newState);
|
||||
});
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ class PublicProfile extends React.Component {
|
|||
renderProfile() {
|
||||
if (!this.state.userProfile) return <NotFound header="Profile not found" />;
|
||||
|
||||
return <Profile profile={this.state.userProfile} user={this.state.user} />;
|
||||
return <Profile profile={this.state.userProfile} user={this.state.user} history={this.props.history} />;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { browserHistory } from 'react-router';
|
||||
import { Helmet } from "react-helmet";
|
||||
import classNames from 'classnames';
|
||||
import qs from "qs";
|
||||
import DebounceInput from 'react-debounce-input';
|
||||
import Select from 'react-select';
|
||||
import ReactGA from 'react-ga';
|
||||
|
@ -31,18 +31,19 @@ class Search extends React.Component {
|
|||
}
|
||||
|
||||
getSearchCriteria(props) {
|
||||
let query = qs.parse(props.location.search.substring(1));
|
||||
let criteria = {
|
||||
keywordSearched: props.location.query.keyword
|
||||
keywordSearched: query.keyword
|
||||
};
|
||||
|
||||
if (this.props.moderation) {
|
||||
// the following states are only useful on moderation mode
|
||||
if (props.location.query.featured === `True`) {
|
||||
criteria.featured = props.location.query.featured;
|
||||
if (query.featured === `True`) {
|
||||
criteria.featured = query.featured;
|
||||
}
|
||||
criteria.moderationState = {
|
||||
value: ``,
|
||||
label: props.location.query.moderationstate || DEFAULT_MODERATION_FILTER
|
||||
label: query.moderationstate || DEFAULT_MODERATION_FILTER
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -53,7 +54,7 @@ class Search extends React.Component {
|
|||
let keywordSearched = this.state.keywordSearched;
|
||||
let moderationState = this.state.moderationState;
|
||||
let featured = this.state.featured;
|
||||
let location = { pathname: this.props.router.location.pathname };
|
||||
let location = { pathname: this.props.location.pathname };
|
||||
let query = {};
|
||||
|
||||
if ( keywordSearched ) {
|
||||
|
@ -69,8 +70,8 @@ class Search extends React.Component {
|
|||
query.moderationstate = moderationState.label;
|
||||
}
|
||||
|
||||
location.query = query;
|
||||
browserHistory.push(location);
|
||||
location.search = `?${qs.stringify(query)}`;
|
||||
this.props.history.push(location);
|
||||
}
|
||||
|
||||
handleInputChange(event) {
|
||||
|
|
81
routes.jsx
81
routes.jsx
|
@ -1,8 +1,9 @@
|
|||
import React from 'react';
|
||||
import ReactGA from 'react-ga';
|
||||
import { Route, IndexRoute, IndexRedirect } from 'react-router';
|
||||
import { withRouter } from 'react-router';
|
||||
import { Switch, Route, Redirect } from 'react-router-dom';
|
||||
import { Helmet } from "react-helmet";
|
||||
import pageSettings from './js/app-page-settings';
|
||||
import Analytics from './js/analytics.js';
|
||||
import env from "./config/env.generated.json";
|
||||
|
||||
import ProjectLoader from './components/project-loader/project-loader.jsx';
|
||||
|
@ -49,30 +50,65 @@ const Latest = () => {
|
|||
};
|
||||
|
||||
const Help = (router) => {
|
||||
let searchParam = { key: `help_type`, value: router.params.helpType };
|
||||
let searchParam = { key: `help_type`, value: router.match.params.helpType };
|
||||
return <SingleFilterCriteriaPage searchParam={searchParam} headerLabel="Help" />;
|
||||
};
|
||||
|
||||
const Tag = (router) => {
|
||||
let searchParam = { key: `tag`, value: router.params.tag };
|
||||
let searchParam = { key: `tag`, value: router.match.params.tag };
|
||||
return <SingleFilterCriteriaPage searchParam={searchParam} headerLabel="Tag" />;
|
||||
};
|
||||
|
||||
const Main = () => (
|
||||
<Switch>
|
||||
<Route exact path="/" render={() => <Redirect to="/featured"/>} />
|
||||
<Route path="/featured" component={Featured} />
|
||||
<Route path="/latest" component={Latest} />
|
||||
<Route path="/favs" component={Bookmarks} />
|
||||
<Route exact path="/issues" component={Issues} />
|
||||
<Route path="/issues/:issue" component={Issue} />
|
||||
<Route path="/entry/:entryId" component={Entry} />
|
||||
<Route path="/add" component={Add} onEnter={() => { if (typeof window !== `undefined`) { window.scroll(0, 0); } }} />
|
||||
<Route path="/submitted" component={Submitted} />
|
||||
<Route path="/search" component={Search} />
|
||||
<Route exact path="/tags" render={() => <Redirect to="/latest"/>} />
|
||||
<Route path="/tags/:tag" component={Tag} />
|
||||
<Route exact path="/help" render={() => <Redirect to="/latest"/>} />
|
||||
<Route path="/help/:helpType" component={Help} />
|
||||
<Route path="/moderation" component={Moderation} />
|
||||
<Route path="/profile/me" component={MyProfile} />
|
||||
<Route path="/profile/:id" component={PublicProfile} />
|
||||
<Route path="/myprofile" component={ProfileEdit} />
|
||||
<Route path="*" component={NotFound}/>
|
||||
</Switch>
|
||||
);
|
||||
|
||||
const NavbarWithRouter = withRouter(Navbar);
|
||||
|
||||
class App extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.pageTitle = `Mozilla Network Pulse`;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
Analytics.logPageView();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
Analytics.logPageView();
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<Helmet titleTemplate={`%s - ${this.pageTitle}`}
|
||||
defaultTitle={this.pageTitle}>
|
||||
</Helmet>
|
||||
<Navbar router={this.props.router}/>
|
||||
<NavbarWithRouter />
|
||||
<div id="main" className="container">
|
||||
{this.props.children}
|
||||
<Main />
|
||||
</div>
|
||||
<Footer/>
|
||||
</div>
|
||||
|
@ -80,6 +116,7 @@ class App extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// We have renamed all non user facing "favorites" related variables and text (e.g., favs, faved, etc) to "bookmarks".
|
||||
// This is because we want client side code to match what Pulse API uses (i.e., bookmarks)
|
||||
// For user facing bits like UI labels and URL path we want them to stay as "favorites".
|
||||
|
@ -89,34 +126,4 @@ class App extends React.Component {
|
|||
// PageSettings is used to preserve a project list view state.
|
||||
// Attach route enter hook pageSettings.setCurrentPathname(evt.location.pathname)
|
||||
// *only* to routes that render a list of projects.
|
||||
module.exports = (
|
||||
<Route path="/" component={App}>
|
||||
<IndexRedirect to="/featured" />
|
||||
<Route path="featured" component={Featured} onEnter={evt => pageSettings.setCurrentPathname(evt.location.pathname)} />
|
||||
<Route path="latest" component={Latest} onEnter={evt => pageSettings.setCurrentPathname(evt.location.pathname)} />
|
||||
<Route path="favs" component={Bookmarks} onEnter={evt => pageSettings.setCurrentPathname(evt.location.pathname)} />
|
||||
<Route path="issues">
|
||||
<IndexRoute component={Issues} />
|
||||
<Route path=":issue" component={Issue} onEnter={evt => pageSettings.setCurrentPathname(evt.location.pathname)} />
|
||||
</Route>
|
||||
<Route path="entry/:entryId" component={Entry} onEnter={() => pageSettings.setScrollPosition()} onLeave={() => pageSettings.setRestore(true)} />
|
||||
<Route path="add" component={Add} onEnter={() => { if (typeof window !== `undefined`) { window.scroll(0, 0); } }} />
|
||||
<Route path="submitted" component={Submitted} />
|
||||
<Route path="search" component={Search} onEnter={evt => pageSettings.setCurrentPathname(evt.location.pathname)} />
|
||||
<Route path="tags">
|
||||
<IndexRedirect to="/latest" />
|
||||
<Route path=":tag" component={Tag} onEnter={evt => pageSettings.setCurrentPathname(evt.location.pathname)} />
|
||||
</Route>
|
||||
<Route path="help">
|
||||
<IndexRedirect to="/latest" />
|
||||
<Route path=":helpType" component={Help} onEnter={evt => pageSettings.setCurrentPathname(evt.location.pathname)} />
|
||||
</Route>
|
||||
<Route path="moderation" component={Moderation} onEnter={evt => pageSettings.setCurrentPathname(evt.location.pathname)} />
|
||||
<Route path="profile">
|
||||
<Route path="me" component={MyProfile} onEnter={evt => pageSettings.setCurrentPathname(evt.location.pathname)} />
|
||||
<Route path=":id" component={PublicProfile} onEnter={evt => pageSettings.setCurrentPathname(evt.location.pathname)} />
|
||||
</Route>
|
||||
<Route path="myprofile" component={ProfileEdit} onEnter={evt => pageSettings.setCurrentPathname(evt.location.pathname)} />
|
||||
<Route path="*" component={NotFound}/>
|
||||
</Route>
|
||||
);
|
||||
export default App;
|
||||
|
|
39
server.js
39
server.js
|
@ -4,8 +4,8 @@ import helmet from 'helmet';
|
|||
import { Helmet as ReactHelmet } from "react-helmet";
|
||||
import React from 'react';
|
||||
import { renderToString } from 'react-dom/server';
|
||||
import { match, RouterContext } from 'react-router';
|
||||
import routes from './routes.jsx';
|
||||
import { StaticRouter } from 'react-router';
|
||||
import Main from './routes.jsx';
|
||||
import securityHeaders from './js/security-headers';
|
||||
|
||||
const app = express();
|
||||
|
@ -66,28 +66,21 @@ app.use((req, res, next) => {
|
|||
app.use(express.static(path.resolve(__dirname, `dist`)));
|
||||
|
||||
app.get(`*`, (req, res) => {
|
||||
match({ routes: routes, location: req.url }, (err, redirect, props) => {
|
||||
if (err) {
|
||||
res.status(500).send(err.message);
|
||||
} else if (redirect) {
|
||||
res.redirect(302, redirect.pathname + redirect.search);
|
||||
} else if (props) {
|
||||
// we've got props!
|
||||
// let's match a route and render the corresponding page component
|
||||
const appHtml = renderToString(<RouterContext {...props}/>);
|
||||
const reactHelmet = ReactHelmet.renderStatic();
|
||||
const reactHelmet = ReactHelmet.renderStatic();
|
||||
const context = {}; // context object contains the results of the render
|
||||
|
||||
if (props.components[props.components.length-1].displayName === `not-found`) {
|
||||
// if route matches the "Not Found" route, let's render the "Not Found" 404 page
|
||||
res.status(404).send(renderPage(appHtml,reactHelmet));
|
||||
} else {
|
||||
res.status(200).send(renderPage(appHtml,reactHelmet));
|
||||
}
|
||||
} else {
|
||||
// nothing was matched
|
||||
res.status(404).send(`Not Found`);
|
||||
}
|
||||
});
|
||||
const appHtml = renderToString(
|
||||
<StaticRouter location={req.url} context={context}>
|
||||
<Main />
|
||||
</StaticRouter>
|
||||
);
|
||||
|
||||
if (context.url) {
|
||||
// Somewhere a `<Redirect>` was rendered
|
||||
res.redirect(301, context.url);
|
||||
} else {
|
||||
res.status(context.pageNotFound ? 404 : 200).send(renderPage(appHtml, reactHelmet));
|
||||
}
|
||||
});
|
||||
|
||||
function renderPage(appHtml,reactHelmet) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче