Skip to content

Instantly share code, notes, and snippets.

@jonathanwork
Forked from elnino-ict/actions.js
Created June 18, 2017 00:52
Show Gist options
  • Save jonathanwork/9aa96d839b80f4f57ad89ff5c6d07ddb to your computer and use it in GitHub Desktop.
Save jonathanwork/9aa96d839b80f4f57ad89ff5c6d07ddb to your computer and use it in GitHub Desktop.
React Redux
/**
* Send a login request to the server to retrieve a JWT token.
* @param credentials
* @returns {{type: *, isFetching: boolean, isAuthenticated: boolean, credentials: *}}
*/
function requestLogin() {
return {
type: LOGIN_REQUEST,
isFetching: true,
isAuthenticated: false
}
}
/**
* When a successful response is received from the server, sign in the user.
* @param token
* @returns {{type: *, isFetching: boolean, isAuthenticated: boolean, id_token: *}}
*/
function receiveLogin(token) {
return {
type: LOGIN_SUCCESS,
isFetching: false,
isAuthenticated: true,
token: token
}
}
/**
* Handle errors in the sign in flow
* @param message - The received error message
* @returns {{type: *, isFetching: boolean, isAuthenticated: boolean, message: *}}
*/
export function loginError(message) {
return {
type: LOGIN_FAILURE,
isFetching: false,
isAuthenticated: false,
message: message
}
}
/**
* Sign in a user by making an API request and handling the response. Depending on the response, the function will
* emit a success or error action which will trigger the reducer to change the state accordingly.
* @param credentials
* @param success
* @returns {Function}
*/
export function loginUser(credentials, success) {
let body = {
"email": credentials.email,
"password": credentials.password
};
return dispatch => {
dispatch(requestLogin());
//Make an API call to the login endpoint containing the users credentials
return callApi('POST', PATH_LOGIN, body, state).then(function (response) {
//The call was successful.
response.json().then(token => ({token, response}))
.then(({token, response}) => {
dispatch(receiveLogin(token.token));
success();
}).catch(err => console.log("Error: ", err));
}, function (response) {
//The endpoint returned an error code.
//Here we extract the error, and emit a loginError action containing the message.
response.json().then(object => {
dispatch(loginError(object.errors[0]));
});
});
}
}
class HomePage extends Component {
render() {
// isAuthenticated is mapped from the state to the components properties
// when the component is connected to the state.
const { dispatch, isAuthenticated } = this.props;
return (
<div>
{/* The user is authenticated, show the profile picture */}
{isAuthenticated &&
<ProfilePicture />
}
{/* The user is not authenticated, show the sign in button */}
{!isAuthenticated &&
<SignInButton />
}
<Content />
</div>
);
}
}
HomePage.propTypes = {
dispatch: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool.isRequired
};
function mapStateToProps(state) {
//Depending on your state's structure, extract the relevant parts
//and map them to your properties
//In this example we'll just assume we only have a single boolean flag in our state.
const isAuthenticated = state;
return {
isAuthenticated
}
}
// Wrap the component to inject dispatch and state into it
export default connect(mapStateToProps)(HomePage);
/**
* Reducer to change the application state for all auth state changes
* @param state
* @param action
*/
function auth(state = {
isFetching: false,
isAuthenticated: false,
token: null,
errorMessage: ""
}, action) {
switch (action.type) {
case LOGIN_REQUEST:
return Object.assign({}, state, {
isFetching: true,
isAuthenticated: false,
errorMessage: ""
});
case LOGIN_SUCCESS:
return Object.assign({}, state, {
isFetching: false,
isAuthenticated: true,
errorMessage: "",
token: action.token
});
case LOGIN_FAILURE:
return Object.assign({}, state, {
isFetching: false,
isAuthenticated: false,
errorMessage: action.message
});
default:
return state;
}
}
//When splitting your reducers into separate functions for specific parts of the state
//You have combine them into a single reducer function for redux using the combineReducers function.
export const reducer = combineReducers({
auth
});
export default reducer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment