Skip to content

Commit 5e4306d

Browse files
committed
Merge branch 'feature/react-router-redux-integration' into dev
2 parents 4df8a9e + 9e79ce5 commit 5e4306d

File tree

17 files changed

+186
-98
lines changed

17 files changed

+186
-98
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
"react-redux": "^4.4.5",
123123
"react-router": "^2.3.0",
124124
"react-router-active-component": "^4.0.0",
125+
"react-router-redux": "^4.0.6",
125126
"redux": "^3.5.2",
126127
"redux-form": "^6.1.0",
127128
"redux-thunk": "^2.1.0",

src/client/index.js

+23-3
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,50 @@ import { createStore, applyMiddleware } from 'redux';
44
import { Provider } from 'react-redux';
55
import thunk from 'redux-thunk';
66
import { match, Router, browserHistory } from 'react-router';
7+
import {
8+
routerMiddleware,
9+
syncHistoryWithStore,
10+
push,
11+
} from 'react-router-redux';
712
import LocaleProvider from '../common/components/utils/LocaleProvider';
813
import rootReducer from '../common/reducers';
914
import getRoutes from '../common/routes';
1015
import setupLocale from './setupLocale';
1116
import setupNProgress from './setupNProgress';
1217
import setupGA from './setupGA';
1318
import { setApiEngine } from '../common/actions/apiEngine';
19+
import { removeCookie } from '../common/actions/cookieActions';
1420
import ApiEngine from '../common/utils/ApiEngine';
1521

1622
setupNProgress();
1723
setupLocale();
1824
let logPageView = setupGA();
1925
const initialState = window.__INITIAL_STATE__;
20-
let store = createStore(rootReducer, initialState, applyMiddleware(thunk));
26+
let store = createStore(
27+
rootReducer,
28+
initialState,
29+
applyMiddleware(
30+
routerMiddleware(browserHistory),
31+
thunk
32+
)
33+
);
2134

2235
let apiEngine = new ApiEngine();
2336
store.dispatch(setApiEngine(apiEngine));
2437

38+
let { redirect } = store.getState().cookies;
39+
if (redirect) {
40+
store.dispatch(push(redirect));
41+
store.dispatch(removeCookie('redirect'));
42+
}
43+
2544
// refs:
2645
// - <http://www.jianshu.com/p/b3ff1f53faaf>
2746
// - <https://github.com/ryanflorence/example-react-router-server-rendering-lazy-routes>
47+
let history = syncHistoryWithStore(browserHistory, store);
2848
let routes = getRoutes(store);
2949
match({
30-
history: browserHistory,
50+
history,
3151
routes,
3252
}, (error, redirectLocation, renderProps) => {
3353
if (error) {
@@ -37,7 +57,7 @@ match({
3757
<Provider store={store}>
3858
<LocaleProvider>
3959
<Router
40-
history={browserHistory}
60+
history={history}
4161
onUpdate={logPageView}
4262
{...renderProps}
4363
>

src/common/actions/routeActions.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { push } from 'react-router-redux';
2+
import { setCookie } from './cookieActions';
3+
4+
export const redirect = (path) => {
5+
return (dispatch) => {
6+
dispatch(setCookie('redirect', path));
7+
dispatch(push(path));
8+
};
9+
};

src/common/components/forms/LoginForm.js

+16-17
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import React, { Component, PropTypes } from 'react';
1+
import React, { Component } from 'react';
2+
import { connect } from 'react-redux';
3+
import { push } from 'react-router-redux';
24
import { Field, reduxForm } from 'redux-form';
35
import Button from 'react-bootstrap/lib/Button';
46
// import validator from 'validator';
@@ -33,32 +35,31 @@ class LoginForm extends Component {
3335
}
3436

3537
_login(json) {
36-
return this.context.store.dispatch(loginUser({
38+
return this.props.dispatch(loginUser({
3739
token: json.token,
3840
data: json.user,
3941
}));
4042
}
4143

4244
_handleSubmit(formData) {
43-
return userAPI(this.context.store.getState().apiEngine)
45+
// let { store } = this.context;
46+
let { dispatch, apiEngine } = this.props;
47+
48+
return userAPI(apiEngine)
4449
.login(formData)
4550
.catch((err) => {
46-
this.context.store.dispatch(pushErrors(err));
51+
dispatch(pushErrors(err));
4752
throw err;
4853
})
4954
.then((json) => {
5055
if (json.isAuth) {
5156
this.login(json).then(() => {
5257
// redirect to the origin path before logging in
53-
const { location } = this.props;
54-
if (location && location.state && location.state.nextPathname) {
55-
this.context.router.push(location.state.nextPathname);
56-
} else {
57-
this.context.router.push('/');
58-
}
58+
let { next } = this.props.routing.locationBeforeTransitions.query;
59+
dispatch(push(next || '/'));
5960
});
6061
} else {
61-
this.context.store.dispatch(pushErrors([{
62+
dispatch(pushErrors([{
6263
title: 'User Not Exists',
6364
detail: 'You may type wrong email or password.',
6465
}]));
@@ -100,12 +101,10 @@ class LoginForm extends Component {
100101
}
101102
};
102103

103-
LoginForm.contextTypes = {
104-
store: PropTypes.object.isRequired,
105-
router: PropTypes.any.isRequired,
106-
};
107-
108104
export default reduxForm({
109105
form: 'login',
110106
validate,
111-
})(LoginForm);
107+
})(connect(state => ({
108+
apiEngine: state.apiEngine,
109+
routing: state.routing,
110+
}))(LoginForm));

src/common/components/forms/RegisterForm.js

+11-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import React, { Component, PropTypes } from 'react';
1+
import React, { Component } from 'react';
2+
import { connect } from 'react-redux';
3+
import { push } from 'react-router-redux';
24
import { Field, reduxForm } from 'redux-form';
35
import Button from 'react-bootstrap/lib/Button';
46
// import validator from 'validator';
@@ -43,14 +45,16 @@ class RegisterForm extends Component {
4345
}
4446

4547
_handleSubmit(formData) {
46-
return userAPI(this.context.store.getState().apiEngine)
48+
let { dispatch, apiEngine } = this.props;
49+
50+
return userAPI(apiEngine)
4751
.register(formData)
4852
.catch((err) => {
49-
this.context.store.dispatch(pushErrors(err));
53+
dispatch(pushErrors(err));
5054
throw err;
5155
})
5256
.then((json) => {
53-
this.context.router.push('/');
57+
dispatch(push('/'));
5458
});
5559
}
5660

@@ -99,14 +103,11 @@ class RegisterForm extends Component {
99103
}
100104
};
101105

102-
RegisterForm.contextTypes = {
103-
store: PropTypes.any.isRequired,
104-
router: PropTypes.any.isRequired,
105-
};
106-
107106
export default reduxForm({
108107
form: 'register',
109108
validate,
110109
asyncValidate,
111110
asyncBlurFields: ['email'],
112-
})(RegisterForm);
111+
})(connect(state => ({
112+
apiEngine: state.apiEngine,
113+
}))(RegisterForm));
+15-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
1-
import React from 'react';
1+
import React, { PropTypes } from 'react';
22
import Grid from 'react-bootstrap/lib/Grid';
33
import Navigation from '../utils/Navigation';
44
import ErrorList from '../utils/ErrorList';
55

6-
const PageLayout = ({ children, ...rest }) => (
6+
let PageLayout = ({ hasGrid, children, ...rest }) => (
77
<div>
88
<Navigation />
99
<ErrorList />
10-
<Grid {...rest}>
11-
{children}
12-
</Grid>
10+
{hasGrid ? (
11+
<Grid {...rest}>
12+
{children}
13+
</Grid>
14+
) : children}
1315
</div>
1416
);
1517

18+
PageLayout.propTypes = {
19+
hasGrid: PropTypes.bool,
20+
};
21+
22+
PageLayout.defaultProps = {
23+
hasGrid: true,
24+
};
25+
1626
export default PageLayout;

src/common/components/pages/admin/user/ListPage.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { Component } from 'react';
22
import { connect } from 'react-redux';
3-
import { withRouter } from 'react-router';
3+
import { push } from 'react-router-redux';
44
import PageHeader from 'react-bootstrap/lib/PageHeader';
55
import Table from 'react-bootstrap/lib/Table';
66
import Resources from '../../../../constants/Resources';
@@ -24,7 +24,7 @@ class ListPage extends Component {
2424
}
2525

2626
componentDidUpdate(prevProps) {
27-
let { dispatch, apiEngine, page, router, location } = this.props;
27+
let { dispatch, apiEngine, page, location } = this.props;
2828

2929
if (prevProps.page.current !== page.current) {
3030
userAPI(apiEngine)
@@ -36,10 +36,10 @@ class ListPage extends Component {
3636
.then((json) => {
3737
this.setState({ users: json.users });
3838
dispatch(setPage(Resources.USER, json.page));
39-
router.push({
39+
dispatch(push({
4040
pathname: location.pathname,
4141
query: { page: json.page.current },
42-
});
42+
}));
4343
});
4444
}
4545
}
@@ -78,7 +78,7 @@ class ListPage extends Component {
7878
}
7979
}
8080

81-
export default withRouter(connect(state => ({
81+
export default connect(state => ({
8282
apiEngine: state.apiEngine,
8383
page: state.pages[Resources.USER] || {},
84-
}))(ListPage));
84+
}))(ListPage);

src/common/components/pages/todo/ListPage.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { Component } from 'react';
22
import { connect } from 'react-redux';
3-
import { withRouter } from 'react-router';
3+
import { push } from 'react-router-redux';
44
import PageHeader from 'react-bootstrap/lib/PageHeader';
55
import Resources from '../../../constants/Resources';
66
import todoAPI from '../../../api/todo';
@@ -93,7 +93,7 @@ class ListPage extends Component {
9393
}
9494

9595
componentDidUpdate(prevProps) {
96-
let { dispatch, apiEngine, page, router, location } = this.props;
96+
let { dispatch, apiEngine, page, location } = this.props;
9797

9898
if (prevProps.page.current !== page.current) {
9999
todoAPI(apiEngine)
@@ -105,10 +105,10 @@ class ListPage extends Component {
105105
.then((json) => {
106106
dispatch(setTodo(json.todos));
107107
dispatch(setPage(Resources.TODO, json.page));
108-
router.push({
108+
dispatch(push({
109109
pathname: location.pathname,
110110
query: { page: json.page.current },
111-
});
111+
}));
112112
});
113113
}
114114
}
@@ -177,8 +177,8 @@ class ListPage extends Component {
177177
}
178178
};
179179

180-
export default withRouter(connect(state => ({
180+
export default connect(state => ({
181181
apiEngine: state.apiEngine,
182182
todos: state.todos,
183183
page: state.pages[Resources.TODO] || {},
184-
}))(ListPage));
184+
}))(ListPage);
+47-31
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,58 @@
11
import React from 'react';
22
import PageHeader from 'react-bootstrap/lib/PageHeader';
3+
import Alert from 'react-bootstrap/lib/Alert';
34
import Grid from 'react-bootstrap/lib/Grid';
45
import Row from 'react-bootstrap/lib/Row';
56
import Col from 'react-bootstrap/lib/Col';
67
import PageLayout from '../../layouts/PageLayout';
78
import Head from '../../widgets/Head';
89
import LoginForm from '../../forms/LoginForm';
910

10-
const LoginPage = (props) => (
11-
<PageLayout>
12-
<Head
13-
links={[
14-
'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-social/5.0.0/bootstrap-social.min.css',
15-
]}
16-
/>
17-
<PageHeader>Login</PageHeader>
18-
<Grid>
19-
<Row>
20-
<Col md={9}>
21-
<LoginForm location={props.location} />
22-
</Col>
23-
<Col md={3}>
24-
<a
25-
href="/auth/facebook"
26-
className="btn btn-block btn-social btn-facebook"
27-
>
28-
<span className="fa fa-facebook"></span>Login with Facebook
29-
</a>
30-
<a
31-
href="/auth/linkedin"
32-
className="btn btn-block btn-social btn-linkedin"
33-
>
34-
<span className="fa fa-linkedin"></span>Login with LinkedIn
35-
</a>
36-
</Col>
37-
</Row>
38-
</Grid>
39-
</PageLayout>
40-
);
11+
let LoginPage = ({ location }) => {
12+
let { next } = location.query;
13+
let search = next ? '?next=' + next : '';
14+
15+
return (
16+
<PageLayout hasGrid={false}>
17+
<Head
18+
links={[
19+
'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-social/5.0.0/bootstrap-social.min.css',
20+
]}
21+
/>
22+
<Grid>
23+
<PageHeader>Login</PageHeader>
24+
<Row>
25+
<Col md={12}>
26+
{next && (
27+
<Alert bsStyle="warning">
28+
<strong>Authentication Required</strong>
29+
{' '}Please login first.
30+
</Alert>
31+
)}
32+
</Col>
33+
</Row>
34+
<Row>
35+
<Col md={9}>
36+
<LoginForm />
37+
</Col>
38+
<Col md={3}>
39+
<a
40+
href={`/auth/facebook${search}`}
41+
className="btn btn-block btn-social btn-facebook"
42+
>
43+
<span className="fa fa-facebook"></span>Login with Facebook
44+
</a>
45+
<a
46+
href={`/auth/linkedin${search}`}
47+
className="btn btn-block btn-social btn-linkedin"
48+
>
49+
<span className="fa fa-linkedin"></span>Login with LinkedIn
50+
</a>
51+
</Col>
52+
</Row>
53+
</Grid>
54+
</PageLayout>
55+
);
56+
};
4157

4258
export default LoginPage;

0 commit comments

Comments
 (0)