Auth services added & user reducer
This commit is contained in:
@@ -65,6 +65,7 @@
|
||||
"redux": "^3.0.2",
|
||||
"redux-auth": "0.0.2",
|
||||
"redux-batched-subscribe": "^0.1.4",
|
||||
"redux-logger": "^2.5.2",
|
||||
"redux-multi": "^0.1.9",
|
||||
"redux-router": "^1.0.0-beta7",
|
||||
"redux-thunk": "^1.0.3",
|
||||
|
||||
@@ -6,6 +6,7 @@ import React from "react";
|
||||
import { createStore, compose, applyMiddleware, combineReducers} from "redux";
|
||||
import { Provider} from "react-redux";
|
||||
import thunk from "redux-thunk";
|
||||
import createLogger from 'redux-logger';
|
||||
|
||||
import { Route, IndexRoute, Link, IndexLink } from "react-router";
|
||||
import { ReduxRouter} from "redux-router";
|
||||
@@ -24,6 +25,8 @@ import { reduxReactRouter as serverRouter } from "redux-router/server";
|
||||
import { connect } from 'react-redux';
|
||||
import { pushState } from 'redux-router';
|
||||
|
||||
import { requireAuthentication } from './components/AuthComponent';
|
||||
|
||||
//import demoButtons from "./reducers/request-test-buttons";
|
||||
//import demoUi from "./reducers/demo-ui";
|
||||
import Container from "./components/partials/Container";
|
||||
@@ -72,59 +75,6 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
|
||||
// }, 0);
|
||||
//};
|
||||
|
||||
const requireAuth = next =>
|
||||
(nextState, transition, cb) => {
|
||||
debugger;
|
||||
if (!auth.isLoggedIn()) {
|
||||
transition.to('/login', null, {redirect: nextState.location});
|
||||
return;
|
||||
}
|
||||
next(nextState, transition);
|
||||
};
|
||||
|
||||
const mw = compose(requireAuth);
|
||||
|
||||
const requireAuthentication = (Component) => {
|
||||
class AuthenticatedComponent extends React.Component {
|
||||
|
||||
componentWillMount() {
|
||||
this.checkAuth();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.checkAuth();
|
||||
}
|
||||
|
||||
checkAuth() {
|
||||
debugger;
|
||||
if (!this.props.isAuthenticated) {
|
||||
let redirectAfterLogin = this.props.location.pathname;
|
||||
this.props.dispatch(pushState(null, `/signin?next=${redirectAfterLogin}`));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
debugger;
|
||||
return (
|
||||
<div>
|
||||
{this.props.isAuthenticated === true
|
||||
? <Component {...this.props}/>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
token: state.auth.token,
|
||||
userName: state.auth.userName,
|
||||
isAuthenticated: state.auth.isAuthenticated
|
||||
});
|
||||
|
||||
return connect(mapStateToProps)(AuthenticatedComponent);
|
||||
};
|
||||
|
||||
// define app routes
|
||||
// <Route path="account" component={Account} onEnter={requireAuth} />
|
||||
@@ -132,12 +82,10 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
|
||||
|
||||
const routes = (
|
||||
<Route path="/" component={App}>
|
||||
<IndexRoute component={MyAccounts} />
|
||||
<Route onEnter={mw} path="acc" component={Account} />
|
||||
|
||||
<IndexRoute component={requireAuthentication(MyAccounts)} />
|
||||
<Route path="signin" component={SignIn} />
|
||||
<Route path="register" component={SignUp} />
|
||||
<Route path="account/:id" component={Account} />
|
||||
<Route path="account/:accountId" component={requireAuthentication(Account)} />
|
||||
</Route>
|
||||
);
|
||||
|
||||
@@ -148,6 +96,7 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
|
||||
// create the redux store
|
||||
const store = compose(
|
||||
applyMiddleware(thunk),
|
||||
applyMiddleware(createLogger()),
|
||||
reduxReactRouter({
|
||||
createHistory: createHistoryMethod,
|
||||
routes
|
||||
@@ -158,7 +107,7 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
|
||||
/**
|
||||
* The React Router 1.0 routes for both the server and the client.
|
||||
*/
|
||||
return store.dispatch(reduxAuthConfigure([
|
||||
return store.dispatch(((() => { debugger; })() , reduxAuthConfigure)([
|
||||
{
|
||||
default: {
|
||||
//apiUrl: __API_URL__
|
||||
@@ -189,7 +138,14 @@ export function initialize({cookies, isServer, currentLocation, userAgent} = {})
|
||||
], {
|
||||
cookies,
|
||||
isServer,
|
||||
currentLocation
|
||||
currentLocation,
|
||||
tokenFormat: {
|
||||
"access-token": "{{ access-token }}",
|
||||
"uid": "true"
|
||||
},
|
||||
initialCredentials: {
|
||||
'uid': 123
|
||||
}
|
||||
})).then(({ redirectPath, blank } = {}) => {
|
||||
// hack for material-ui server-side rendering.
|
||||
// see https://github.com/callemall/material-ui/pull/2007
|
||||
|
||||
35
js-frontend/src/actions/auth.js
Normal file
35
js-frontend/src/actions/auth.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Created by andrew on 25/02/16.
|
||||
*/
|
||||
import T from '../constants/ACTION_TYPES';
|
||||
|
||||
export function configureStart({...props} = {}) {
|
||||
return {
|
||||
...props,
|
||||
type: T.AUTH.CONFIGURE_START
|
||||
};
|
||||
}
|
||||
export function configureComplete({config, ...props} = {}) {
|
||||
return {
|
||||
...props,
|
||||
type: T.AUTH.CONFIGURE_COMPLETE,
|
||||
config
|
||||
};
|
||||
}
|
||||
export function configureError({errors, ...props} = {}) {
|
||||
return {
|
||||
...props,
|
||||
type: T.AUTH.CONFIGURE_ERROR,
|
||||
errors
|
||||
};
|
||||
}
|
||||
|
||||
export function authenticateStart() {
|
||||
return { type: T.AUTH.AUTHENTICATE_START };
|
||||
}
|
||||
export function authenticateComplete(user) {
|
||||
return { type: T.AUTH.AUTHENTICATE_COMPLETE, user };
|
||||
}
|
||||
export function authenticateError(errors) {
|
||||
return { type: T.AUTH.AUTHENTICATE_ERROR, errors };
|
||||
}
|
||||
43
js-frontend/src/components/AuthComponent.js
Normal file
43
js-frontend/src/components/AuthComponent.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Created by andrew on 21/02/16.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { pushState } from 'redux-router';
|
||||
|
||||
export function requireAuthentication(Component) {
|
||||
|
||||
class AuthComponent extends React.Component {
|
||||
|
||||
componentWillMount() {
|
||||
debugger;
|
||||
if (!this.props.isAuthenticated) {
|
||||
|
||||
// redirect to login and add next param so we can redirect again after login
|
||||
const redirectAfterLogin = this.props.location.pathname;
|
||||
this.props.dispatch(pushState(null, `/signin?next=${redirectAfterLogin}`));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
// render the component that requires auth (passed to this wrapper)
|
||||
return (
|
||||
<Component {...this.props} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps =
|
||||
(state) => {
|
||||
debugger;
|
||||
return ({
|
||||
token: state.auth.token,
|
||||
//userName: state.auth.userName,
|
||||
//isAuthenticated: state.auth.isAuthenticated
|
||||
isAuthenticated: state.auth.getIn(['user', 'isSignedIn'])
|
||||
})
|
||||
};
|
||||
|
||||
return connect(mapStateToProps)(AuthComponent);
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
import React, { PropTypes } from "react";
|
||||
import { Grid, Col, Navbar, NavItem, Nav, NavbarBrand, Footer } from "react-bootstrap";
|
||||
import { LinkContainer } from "react-router-bootstrap";
|
||||
import { SignOutButton } from "redux-auth/bootstrap-theme";
|
||||
|
||||
//if (!global.__SERVER__ && !global.__TEST__) {
|
||||
// require("../../styles/main.scss");
|
||||
@@ -29,6 +30,9 @@ class Container extends React.Component {
|
||||
<NavItem eventKey={2}>Account</NavItem>
|
||||
</LinkContainer>
|
||||
</Nav>
|
||||
<Nav right={true}>
|
||||
<SignOutButton></SignOutButton>
|
||||
</Nav>
|
||||
</Navbar>
|
||||
|
||||
<Grid className="content">
|
||||
|
||||
@@ -4,6 +4,20 @@ export default defineActionTypes({
|
||||
/*
|
||||
* View model
|
||||
*/
|
||||
AUTH: `
|
||||
CONFIGURE_START
|
||||
CONFIGURE_COMPLETE
|
||||
CONFIGURE_ERROR
|
||||
AUTHENTICATE_START
|
||||
AUTHENTICATE_COMPLETE
|
||||
AUTHENTICATE_ERROR
|
||||
SIGN_IN_START
|
||||
SIGN_IN_COMPLETE
|
||||
SIGN_IN_ERROR
|
||||
SIGN_IN_FORM_UPDATE
|
||||
SIGN_OUT_START
|
||||
SIGN_OUT_COMPLETE
|
||||
`,
|
||||
|
||||
DOCUMENT_LIST_VIEW: `
|
||||
SET_QUERY
|
||||
@@ -32,5 +46,5 @@ export default defineActionTypes({
|
||||
NAVIGATION: `
|
||||
START
|
||||
COMPLETE
|
||||
`,
|
||||
`
|
||||
})
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
*/
|
||||
import React, {PropTypes} from "react";
|
||||
import auth from "redux-auth";
|
||||
import * as BS from "react-bootstrap";
|
||||
|
||||
import Input from "./Input";
|
||||
import ButtonLoader from "./ButtonLoader";
|
||||
import { emailSignInFormUpdate, emailSignIn } from "redux-auth";
|
||||
@@ -54,7 +56,6 @@ class EmailSignInForm extends React.Component {
|
||||
handleSubmit (event) {
|
||||
event.preventDefault();
|
||||
let formData = this.props.auth.getIn(["emailSignIn", this.getEndpoint(), "form"]).toJS();
|
||||
debugger;
|
||||
this.props.dispatch(emailSignIn(formData, this.getEndpoint()));
|
||||
}
|
||||
|
||||
@@ -71,6 +72,7 @@ class EmailSignInForm extends React.Component {
|
||||
className="email-sign-in-email"
|
||||
label="Email"
|
||||
placeholder="Email"
|
||||
name="email"
|
||||
disabled={disabled}
|
||||
value={this.props.auth.getIn(["emailSignIn", this.getEndpoint(), "form", "email"])}
|
||||
errors={this.props.auth.getIn(["emailSignIn", this.getEndpoint(), "errors", "email"])}
|
||||
|
||||
@@ -7,6 +7,7 @@ import Input from "./Input";
|
||||
import ButtonLoader from "./ButtonLoader";
|
||||
import { emailSignUpFormUpdate, emailSignUp } from "redux-auth";
|
||||
import IndexPanel from "./../../components/partials/IndexPanel";
|
||||
import { customerInfoMap } from '../../entities/formToPayloadMappers';
|
||||
|
||||
import { Glyphicon } from "react-bootstrap";
|
||||
import { connect } from "react-redux";
|
||||
@@ -45,8 +46,8 @@ class EmailSignUpForm extends React.Component {
|
||||
handleSubmit (event) {
|
||||
event.preventDefault();
|
||||
let formData = this.props.auth.getIn(["emailSignUp", this.getEndpoint(), "form"]).toJS();
|
||||
debugger;
|
||||
this.props.dispatch(emailSignUp(formData, this.getEndpoint()));
|
||||
console.log(customerInfoMap(formData));
|
||||
this.props.dispatch(emailSignUp(customerInfoMap(formData), this.getEndpoint()));
|
||||
}
|
||||
|
||||
render () {
|
||||
@@ -61,6 +62,7 @@ class EmailSignUpForm extends React.Component {
|
||||
onSubmit={this.handleSubmit.bind(this)}>
|
||||
|
||||
<IndexPanel header="basic">
|
||||
|
||||
<Input type="text"
|
||||
label="First name"
|
||||
placeholder="First name"
|
||||
|
||||
30
js-frontend/src/entities/formToPayloadMappers.js
Normal file
30
js-frontend/src/entities/formToPayloadMappers.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Created by andrew on 21/02/16.
|
||||
*/
|
||||
export const customerInfoMap = ({
|
||||
ssn,
|
||||
address1,
|
||||
address2,
|
||||
city, //: "Moscow"
|
||||
email, //: "arevinsky@gmail.com"
|
||||
fname, //: "Andrew"
|
||||
lname, //: "Revinsky"
|
||||
phone, //: "+79031570864"
|
||||
state, //: "Kentucky"
|
||||
zip //: "125315"
|
||||
}) => ({
|
||||
"name": {
|
||||
"firstName": fname,
|
||||
"lastName": lname
|
||||
},
|
||||
email,
|
||||
ssn,
|
||||
"phoneNumber": phone,
|
||||
"address": {
|
||||
"street1": address1,
|
||||
"street2": address2,
|
||||
city,
|
||||
state,
|
||||
"zipCode": zip
|
||||
}
|
||||
});
|
||||
3
js-frontend/src/reducers/auth/authenticate.js
Normal file
3
js-frontend/src/reducers/auth/authenticate.js
Normal file
@@ -0,0 +1,3 @@
|
||||
/**
|
||||
* Created by andrew on 25/02/16.
|
||||
*/
|
||||
3
js-frontend/src/reducers/auth/configure.js
Normal file
3
js-frontend/src/reducers/auth/configure.js
Normal file
@@ -0,0 +1,3 @@
|
||||
/**
|
||||
* Created by andrew on 25/02/16.
|
||||
*/
|
||||
143
js-frontend/src/reducers/auth/index.js
Normal file
143
js-frontend/src/reducers/auth/index.js
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Created by andrew on 25/02/16.
|
||||
*/
|
||||
import T from '../../constants/ACTION_TYPES';
|
||||
|
||||
const configInitialState = {
|
||||
loading: true,
|
||||
errors: null,
|
||||
config: null
|
||||
};
|
||||
|
||||
export const configReducer = (state = {...configInitialState}, action) => {
|
||||
switch(action.type) {
|
||||
case T.AUTH.CONFIGURE_START:
|
||||
return {
|
||||
...state,
|
||||
loading: true
|
||||
};
|
||||
case T.AUTH.CONFIGURE_COMPLETE:
|
||||
const { config } = action;
|
||||
return {
|
||||
...state,
|
||||
loading: false,
|
||||
errors: null,
|
||||
config
|
||||
};
|
||||
case T.AUTH.CONFIGURE_ERROR:
|
||||
const { errors } = action;
|
||||
return {
|
||||
...state,
|
||||
loading: false,
|
||||
errors
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const authInitialState = {
|
||||
loading: false,
|
||||
valid: false,
|
||||
errors: null
|
||||
};
|
||||
export const authReducer = (state = {...authInitialState}, action) => {
|
||||
switch(action.type) {
|
||||
case T.AUTH.AUTHENTICATE_START: return {...state, loading: true };
|
||||
case T.AUTH.AUTHENTICATE_COMPLETE: return {...state, loading: false,
|
||||
errors: null,
|
||||
valid: true};
|
||||
case T.AUTH.AUTHENTICATE_ERROR: return {...state, loading: false,
|
||||
errors: "Invalid token",
|
||||
valid: false};
|
||||
|
||||
default: return state;
|
||||
}
|
||||
};
|
||||
|
||||
const signInInitialState = {
|
||||
loading: false,
|
||||
errors: null,
|
||||
form: {}
|
||||
};
|
||||
export const signInReducer = (state = { ...signInInitialState, form: {...signInInitialState.form }}, action) => {
|
||||
switch(action.type) {
|
||||
case T.AUTH.SIGN_IN_START:
|
||||
return {
|
||||
...state,
|
||||
loading: true
|
||||
};
|
||||
case T.AUTH.SIGN_IN_COMPLETE:
|
||||
return {
|
||||
...signInInitialState,
|
||||
form: { ...signInInitialState.form }
|
||||
};
|
||||
case T.AUTH.SIGN_IN_ERROR:
|
||||
const { errors } = action;
|
||||
return {
|
||||
...state,
|
||||
loading: false,
|
||||
errors
|
||||
};
|
||||
case T.AUTH.SIGN_IN_FORM_UPDATE:
|
||||
const { key, value } = action;
|
||||
return {
|
||||
...state,
|
||||
form: {
|
||||
...state.form,
|
||||
[key]: value
|
||||
}
|
||||
};
|
||||
default: return state;
|
||||
}
|
||||
};
|
||||
|
||||
const signOutInitialState = {
|
||||
loading: false,
|
||||
errors: null
|
||||
};
|
||||
|
||||
export const signOutReducer = (state = {...signOutInitialState}, action) => {
|
||||
switch(action.type) {
|
||||
case T.AUTH.SIGN_OUT_START:
|
||||
return {
|
||||
...state,
|
||||
loading: true
|
||||
};
|
||||
case T.AUTH.SIGN_OUT_COMPLETE:
|
||||
return {
|
||||
...state,
|
||||
loading: false,
|
||||
errors: null
|
||||
};
|
||||
default: return state;
|
||||
}
|
||||
};
|
||||
|
||||
const userInitalState = {
|
||||
attributes: null,
|
||||
isSignedIn: false
|
||||
};
|
||||
|
||||
export const userReducer = (state = {...userInitalState}, action) => {
|
||||
switch(action.type) {
|
||||
case T.AUTH.AUTHENTICATE_COMPLETE:
|
||||
const { user } = action;
|
||||
return {...state,
|
||||
attributes: user,
|
||||
isSignedIn: true
|
||||
};
|
||||
case T.AUTH.SIGN_IN_COMPLETE:
|
||||
const { user } = action;
|
||||
return {...state,
|
||||
attributes: user.data,
|
||||
isSignedIn: true
|
||||
};
|
||||
case T.AUTH.SIGN_OUT_COMPLETE:
|
||||
case T.AUTH.AUTHENTICATE_ERROR:
|
||||
return {
|
||||
...userInitalState
|
||||
};
|
||||
default: return state;
|
||||
}
|
||||
};
|
||||
3
js-frontend/src/reducers/auth/signin.js
Normal file
3
js-frontend/src/reducers/auth/signin.js
Normal file
@@ -0,0 +1,3 @@
|
||||
/**
|
||||
* Created by andrew on 25/02/16.
|
||||
*/
|
||||
3
js-frontend/src/reducers/auth/signout.js
Normal file
3
js-frontend/src/reducers/auth/signout.js
Normal file
@@ -0,0 +1,3 @@
|
||||
/**
|
||||
* Created by andrew on 25/02/16.
|
||||
*/
|
||||
3
js-frontend/src/reducers/auth/user.js
Normal file
3
js-frontend/src/reducers/auth/user.js
Normal file
@@ -0,0 +1,3 @@
|
||||
/**
|
||||
* Created by andrew on 25/02/16.
|
||||
*/
|
||||
17
js-frontend/src/services/auth.js
Normal file
17
js-frontend/src/services/auth.js
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Created by andrew on 25/02/16.
|
||||
*/
|
||||
//import * as A from "../actions/auth";
|
||||
import T from '../constants/ACTION_TYPES';
|
||||
import {
|
||||
authenticateStart,
|
||||
authenticateComplete,
|
||||
authenticateError
|
||||
} from '../actions/auth';
|
||||
|
||||
|
||||
export function configure(endpoint = {}, settings = {}) {
|
||||
return dispatch => {
|
||||
dispatch(authenticateStart());
|
||||
};
|
||||
};
|
||||
@@ -7,6 +7,8 @@ import { connect } from "react-redux";
|
||||
|
||||
//import ButtonLoader from "./ButtonLoader";
|
||||
import { Input } from "react-bootstrap";
|
||||
import * as BS from "react-bootstrap";
|
||||
|
||||
import ButtonLoader from "../controls/bootstrap/ButtonLoader";
|
||||
|
||||
//export {bootstrap, materialUi} from "./views";
|
||||
@@ -16,9 +18,20 @@ import ButtonLoader from "../controls/bootstrap/ButtonLoader";
|
||||
//import { EmailSignInForm } from "redux-auth/bootstrap-theme";
|
||||
import EmailSignInForm from "../controls/bootstrap/EmailSignInForm";
|
||||
|
||||
|
||||
export class SignIn extends React.Component {
|
||||
|
||||
componentWillMount() {
|
||||
debugger;
|
||||
if (this.props.isAuthenticated) {
|
||||
|
||||
debugger;
|
||||
|
||||
//// redirect to login and add next param so we can redirect again after login
|
||||
//const redirectAfterLogin = this.props.location.pathname;
|
||||
//this.props.dispatch(pushState(null, `/signin?next=${redirectAfterLogin}`));
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const signInProps = {
|
||||
inputProps: {
|
||||
@@ -31,13 +44,18 @@ export class SignIn extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
return <EmailSignInForm />;
|
||||
//return (
|
||||
// <div>
|
||||
// <PageHeader>Sign In First</PageHeader>
|
||||
// <p>Unauthenticated users can't access the account page.</p>
|
||||
// </div>
|
||||
//);
|
||||
return (
|
||||
<BS.Well>
|
||||
<PageHeader>Sign In</PageHeader>
|
||||
<EmailSignInForm {...this.props} />
|
||||
</BS.Well>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default connect(({routes}) => ({routes}))(SignIn);
|
||||
export default connect(({
|
||||
routes,
|
||||
auth
|
||||
}) => ({
|
||||
routes,
|
||||
auth
|
||||
}))(SignIn);
|
||||
|
||||
@@ -5,21 +5,23 @@ import React from "react";
|
||||
//import { PageHeader } from "react-bootstrap";
|
||||
import { connect } from "react-redux";
|
||||
import { PageHeader, OverlayTrigger, Tooltip, Row, ButtonGroup, Table } from "react-bootstrap";
|
||||
import * as BS from "react-bootstrap";
|
||||
import { Link, IndexLink} from "react-router";
|
||||
|
||||
//import { EmailSignUpForm } from "redux-auth/bootstrap-theme"
|
||||
import EmailSignUpForm from "../controls/bootstrap/EmailSignUpForm";
|
||||
|
||||
export class SignUp extends React.Component {
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div>
|
||||
<PageHeader>
|
||||
Register
|
||||
</PageHeader>
|
||||
<Row>
|
||||
<BS.Well>
|
||||
<EmailSignUpForm endpoint="default" />
|
||||
</Row>
|
||||
</BS.Well>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user