Skip to content

Commit

Permalink
feat(social login): social login
Browse files Browse the repository at this point in the history
  • Loading branch information
kakaemma committed Nov 8, 2018
1 parent 27b2cb9 commit e9819dc
Show file tree
Hide file tree
Showing 18 changed files with 555 additions and 61 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"no-unused-expressions": [2, { "allowTernary": true }],
"arrow-parens":0,
"implicit-arrow-linebreak":"off",
"jsx-a11y/label-has-associated-control":0
"jsx-a11y/label-has-associated-control":0,
"no-shadow":"warn"
},
"parser": "babel-eslint",
"plugins": [
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
.env.development.local
.env.test.local
.env.production.local
package-lock.json

npm-debug.log*
yarn-debug.log*
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"prop-types": "^15.6.2",
"react": "^16.6.0",
"react-dom": "^16.6.0",
"react-facebook-login": "^4.1.1",
"react-google-login": "^3.2.1",
"react-notify-toast": "^0.5.0",
"react-redux": "^5.1.0",
"react-router-dom": "^4.3.1",
Expand Down
1 change: 1 addition & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Open+Sans">
Expand Down
13 changes: 13 additions & 0 deletions src/actions/actionCreators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {
SOCIAL_LOGIN_INITIATED,
SOCIAL_LOGIN_SUCCESS,
} from './types';

export const socialLoginInitiated = () => ({
type: SOCIAL_LOGIN_INITIATED,
});


export const socialLoginSuccess = () => ({
type: SOCIAL_LOGIN_SUCCESS,
});
2 changes: 2 additions & 0 deletions src/actions/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export const REGISTER_USER_SUCCESS = 'REGISTER_USER_SUCCESS';
export const REGISTER_USER_ERROR = 'REGISTER_USER_ERROR';
export const LOGIN_USER_SUCCESS = 'LOGIN_USER_SUCCESS';
export const LOGIN_USER_ERROR = 'LOGIN_USER_ERROR';
export const SOCIAL_LOGIN_INITIATED = 'SOCIAL_LOGIN_INITIATED';
export const SOCIAL_LOGIN_SUCCESS = 'SOCIAL_LOGIN_SUCCESS';
35 changes: 35 additions & 0 deletions src/actions/userActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ import {
LOGIN_USER_SUCCESS,
LOGIN_USER_ERROR,
} from './types';
import {
socialLoginInitiated,
socialLoginSuccess,
} from './actionCreators';
import axiosInstance from '../config/axiosInstance';


export const fetchUsers = (postData) => dispatch => {
toast.dismiss();
axiosInstance
Expand Down Expand Up @@ -59,3 +64,33 @@ export const loginUser = payload => async dispatch => {
);
});
};

export const googleLoginUser = (serviceProvider, userData) => (dispatch) => {
dispatch(socialLoginInitiated(true));
return axiosInstance.post(serviceProvider, userData)
.then((res) => {
localStorage.setItem('auth_token', res.data.user.access_token);
dispatch(socialLoginSuccess(true));
toast.success('Signup successful', { autoClose: 3500, hideProgressBar: true });
})
.catch(() => {
toast.error('We can not sign you in if you registered with another social account', { autoClose: 3500, hideProgressBar: true }, {
position: toast.POSITION.TOP_CENTER,
});
});
};

export const facebookLoginUser = (serviceProvider, userData) => (dispatch) => {
dispatch(socialLoginInitiated(true));
return axiosInstance.post(serviceProvider, userData)
.then((res) => {
localStorage.setItem('auth_token', res.data.user.access_token);
dispatch(socialLoginSuccess(true));
toast.success('Signup successful', { autoClose: 3500, hideProgressBar: true });
})
.catch(() => {
toast.error('We can not sign you in if you registered with another social account', { autoClose: 3500, hideProgressBar: true }, {
position: toast.POSITION.TOP_CENTER,
});
});
};
36 changes: 36 additions & 0 deletions src/assets/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,39 @@ header.uvp {
.forgot-password{
color: firebrick;
}
.icon-with-margin {
margin-right: 10px;
}
.google{
background-color: #d34836;
display: inline-block;
background: rgb(209, 72, 54);
color: rgb(255, 255, 255);
width: 150px;
padding-top: 5px;
padding-bottom: 5px;
border-radius: 5px;
border: 1px solid transparent;
font-size: 20px;
font-weight: bold;
font-family: Roboto;
transition: background-color .3s,border-color .3s;
}

.facebook{
font-family: Roboto;
font-weight: bold;
display: inline-block;
border-radius: 5px;
color: #fff;
width: 145px;
padding-top: 5px;
padding-bottom: 5px;
cursor: pointer;
font-size: 20px;
text-decoration: none;
transition: background-color .3s,border-color .3s;
background-color: #4c69ba;
display: inline-block;
border:solid 1px #4c69ba;
}
71 changes: 71 additions & 0 deletions src/components/login/FacebookButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { PureComponent } from 'react';
import { Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import FacebookLogin from 'react-facebook-login';
import PropTypes from 'prop-types';
import { facebookLoginUser } from '../../actions/userActions';

class FacebookButton extends PureComponent {
constructor(props) {
super(props);
this.state = {
redirect: false,
};
}

componentWillReceiveProps(nextProps) {
if (nextProps.isLoggedIn) {
this.setState({
redirect: true,
});
}
}

signup = (userToken) => {
const userData = {
user: {
access_token: userToken,
},
};
const { facebookLoginUser } = this.props;
facebookLoginUser('/api/auth/facebook/', userData);
}

handleFacebookResponse = (response) => {
const token = response.accessToken;
this.signup(token);
}

render() {
const value = this.state;
if (value.redirect) {
const to = { pathname: '/' };
return (
<Redirect to={to} />
);
}
return (
<FacebookLogin
appId="2147542838793839"
fields="name,email,picture"
callback={this.handleFacebookResponse}
icon="fa fa-facebook-square icon-with-margin"
cssClass="facebook"
textButton="Facebook"

/>
);
}
}

const mapStateToProps = (state) => ({
isLoggedIn: state.user.isLoggedIn,
loading: state.user.loading,
});

FacebookButton.propTypes = {
isLoggedIn: PropTypes.bool.isRequired,
facebookLoginUser: PropTypes.func.isRequired,
};
export { FacebookButton as FacebookTest };
export default connect(mapStateToProps, { facebookLoginUser })(FacebookButton);
84 changes: 84 additions & 0 deletions src/components/login/GoogleButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React, { PureComponent } from 'react';
import { Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import GoogleLogin from 'react-google-login';
import PropTypes from 'prop-types';

import { googleLoginUser } from '../../actions/userActions';

class GoogleloginButton extends PureComponent {
constructor(props) {
super(props);
this.state = {
redirect: false,
};
}

componentWillReceiveProps(nextProps) {
if (nextProps.isLoggedIn) {
console.log('is working', nextProps.isLoggedIn);
this.setState({
redirect: true,
});
}
}

signup = (userToken) => {
const userData = {
user: {
access_token: userToken,
},
};

const { googleLoginUser } = this.props;
googleLoginUser('/api/auth/google/', userData);
}

handleGoogleResponse = (response) => {
const token = response.tokenId;
this.signup(token);
}

render() {
const value = this.state;
if (value.redirect) {
const to = { pathname: '/' };
return (
<Redirect to={to} />
);
}
return (
<div>
<GoogleLogin
clientId="1040550554735-0lfo665jrpgkprjkqdvh9njlc46mu6rg.apps.googleusercontent.com"
redirectUri="/"
onSuccess={this.handleGoogleResponse}
onFailure={this.handleGoogleResponse}
className="google"
>
<i className="fa fa-google-plus icon-with-margin" />
<span className="raised-font"> Google</span>

</GoogleLogin>
&nbsp;

</div>

);
}
}

const mapStateToProps = (state) => ({
isLoggedIn: state.user.isLoggedIn,
loading: state.user.loading,
});

GoogleloginButton.propTypes = {
isLoggedIn: PropTypes.bool.isRequired,
googleLoginUser: PropTypes.func.isRequired,
};

export { GoogleloginButton as GoogleTest };
export default connect(
mapStateToProps, { googleLoginUser },
)(GoogleloginButton);
15 changes: 14 additions & 1 deletion src/components/login/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import 'react-toastify/dist/ReactToastify.css';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import '../../assets/App.css';
import { loginUser } from '../../actions/userActions';
import {
loginUser,
facebookLoginUser,
} from '../../actions/userActions';
import GoogleButton from './GoogleButton';
import FacebookButton from './FacebookButton';

export class Login extends Component {
constructor(props) {
Expand Down Expand Up @@ -92,6 +97,14 @@ export class Login extends Component {
<div className="form-group">
<Link className="forgot-password" to="/forgotPassword">Forgot password?</Link>
</div>
<div className="row">
<div className="col-md-6">
<GoogleButton />
</div>
<div className="col-md-6 ">
<FacebookButton facebookLoginUserAction={facebookLoginUser} />
</div>
</div>
</form>
</div>
</div>
Expand Down
18 changes: 18 additions & 0 deletions src/reducers/userReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@ import {
REGISTER_USER_ERROR,
LOGIN_USER_SUCCESS,
LOGIN_USER_ERROR,
SOCIAL_LOGIN_INITIATED,
SOCIAL_LOGIN_SUCCESS,
} from '../actions/types';


const initialState = {
registerUserSuccess: false,
isLoginSuccess: false,
registerUserError: {},
loginError: {},
isLoggedIn: false,
loading: false,
};


const userReducer = (state = initialState, action) => {
switch (action.type) {
case REGISTER_USER_SUCCESS:
Expand All @@ -35,6 +41,18 @@ const userReducer = (state = initialState, action) => {
...state,
loginError: action.payload,
};
case SOCIAL_LOGIN_INITIATED:
return {
...state,
loading: true,
};
case SOCIAL_LOGIN_SUCCESS:
return {
...state,
isLoggedIn: true,
loading: false,
};

default:
return state;
}
Expand Down
Loading

0 comments on commit e9819dc

Please sign in to comment.