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 6, 2018
1 parent 2397d6d commit ce5447a
Show file tree
Hide file tree
Showing 19 changed files with 437 additions and 16,866 deletions.
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
16,803 changes: 0 additions & 16,803 deletions package-lock.json

This file was deleted.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"dependencies": {
"ajv": "^6.5.4",
"axios": "^0.18.0",
"dotenv-webpack": "^1.5.7",
"enzyme": "^3.7.0",
"enzyme-adapter-react-16": "^1.6.0",
"history": "^4.7.2",
Expand All @@ -16,6 +17,9 @@
"react-redux": "^5.1.0",
"react-router-dom": "^4.3.1",
"react-scripts": "2.0.5",
"react-facebook-login": "^4.1.1",
"react-google-login": "^3.2.1",
"react-social-login-buttons": "^2.2.0",
"react-toastify": "^4.4.0",
"redux": "^4.0.1",
"redux-thunk": "^2.3.0"
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
@@ -1,2 +1,4 @@
export const REGISTER_USER_SUCCESS = 'REGISTER_USER_SUCCESS';
export const REGISTER_USER_ERROR = 'REGISTER_USER_ERROR';
export const SOCIAL_LOGIN_INITIATED = 'SOCIAL_LOGIN_INITIATED';
export const SOCIAL_LOGIN_SUCCESS = 'SOCIAL_LOGIN_SUCCESS';
32 changes: 31 additions & 1 deletion src/actions/userActions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { toast } from 'react-toastify';
import { REGISTER_USER_SUCCESS, REGISTER_USER_ERROR } from './types';
import {
socialLoginInitiated,
socialLoginSuccess,
} from './actionCreators';
import axiosInstance from '../config/axiosInstance';


export const fetchUsers = (postData) => dispatch => {
axiosInstance
.post('/api/users/', postData)
Expand All @@ -26,4 +31,29 @@ export const fetchUsers = (postData) => dispatch => {
});
};

export default fetchUsers;

export const googleLoginUser = (serviceProvider, userData) => (dispatch) => {
dispatch(socialLoginInitiated(true));
return axiosInstance.post(serviceProvider, userData)
.then((res) => {
localStorage.setItem('token', res.data.user.access_token);
dispatch(socialLoginSuccess(res));
})
.catch((error) => {
console.log(error);
toast.error(error, { 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) => {
console.log('res', res);
localStorage.setItem('token', res.data.user.access_token);
dispatch(socialLoginSuccess(res));
})
.catch((error) => error);
};
36 changes: 36 additions & 0 deletions src/assets/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,39 @@ header.uvp {
box-shadow: 0 15px 25px rgba(0, 0, 0, .5);
border-radius: 10px;
}
.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: 2px;
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: 2px;
color: #fff;
width: 150px;
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;
}
72 changes: 72 additions & 0 deletions src/components/login/Facebook.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
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 Facebook extends PureComponent {
constructor(props) {
super(props);
this.state = {
redirect: false,
};
}

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

signup = (userToken, serviceProvider) => {
let userData;
userData = {
user: {
access_token: userToken,
},
};
const { facebookLoginUser } = this.props;
facebookLoginUser(serviceProvider, userData);
}

responseFacebook = (response) => {
const token = response.accessToken;
this.signup(token, 'api/auth/facebook/');
}

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.responseFacebook}
icon="fa fa-facebook-square icon-with-margin"
cssClass="facebook"
textButton="Facebook"

/>
);
}
}

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

Facebook.propTypes = {
isLoggedIn: PropTypes.bool.isRequired,
facebookLoginUser: PropTypes.func.isRequired,
};
export { Facebook as FacebookTest };
export default connect(mapStateToProps, { facebookLoginUser })(Facebook);
86 changes: 86 additions & 0 deletions src/components/login/Google.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
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 Googlelogin extends PureComponent {
constructor(props) {
super(props);
this.state = {
redirect: false,
};
}

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

signup = (userToken, serviceProvider) => {
let userData;
if (serviceProvider === 'api/auth/google/') {
userData = {
user: {
access_token: userToken,
},
};
}

if (userData) {
const { googleLoginUser } = this.props;
googleLoginUser(serviceProvider, userData);
}
}

googleResponse = (response) => {
const token = response.tokenId;
this.signup(token, 'api/auth/google/');
}

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.googleResponse}
onFailure={this.googleResponse}
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,
});

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

export { Googlelogin as GoogleTest };
export default connect(mapStateToProps, { googleLoginUser })(Googlelogin);
16 changes: 15 additions & 1 deletion src/components/login/Login.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
import React from 'react';
import Googlelogin from './Google';
import Faceboook from './Facebook';

const Login = () => <h1>Login!</h1>;
const Login = () => (
<div>
<h1>Login!</h1>
<div className="row">
<div className="col-md-2">
<Googlelogin />
</div>
<div className="col-md-2">
<Faceboook />
</div>
</div>
</div>
);

export default Login;
2 changes: 1 addition & 1 deletion src/config/axiosInstance.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios';

const axiosInstance = axios.create({
baseURL: 'https://ah-backend-targaryen-staging.herokuapp.com',
baseURL: 'http://127.0.0.1:8000/',
timeout: 60000,
headers: { 'Content-Type': 'application/json' },
});
Expand Down
23 changes: 22 additions & 1 deletion src/reducers/userReducer.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { REGISTER_USER_SUCCESS, REGISTER_USER_ERROR } from '../actions/types';
import {
REGISTER_USER_SUCCESS,
REGISTER_USER_ERROR,
SOCIAL_LOGIN_INITIATED,
SOCIAL_LOGIN_SUCCESS,
} from '../actions/types';


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


const userReducer = (state = initialState, action) => {
switch (action.type) {
case REGISTER_USER_SUCCESS:
Expand All @@ -17,6 +26,18 @@ const userReducer = (state = initialState, action) => {
...state,
registerUserError: 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
14 changes: 13 additions & 1 deletion src/tests/actions/userActions.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import MockAdapter from 'axios-mock-adapter';
import configureMockStore from 'redux-mock-store';
import { fetchUsers } from '../../actions/userActions';
import { fetchUsers, googleLoginUser } from '../../actions/userActions';
import { REGISTER_USER_SUCCESS, REGISTER_USER_ERROR } from '../../actions/types';
import axiosInstance from '../../config/axiosInstance';
import { SOCIAL_LOGIN_INITIATED } from '../../actions/types';

describe('userAction', () => {
let store;
Expand Down Expand Up @@ -45,4 +46,15 @@ describe('userAction', () => {
],
);
});
it('should have social login initiated', async () => {
const user_data = {
user: {
access_token: 'token',
},
};
const type = [{ type: SOCIAL_LOGIN_INITIATED }];
googleLoginUser('/api/auth/google/', user_data)(store.dispatch);
await flushAllPromises();
expect(store.getActions()).toEqual(type);
});
});
Loading

0 comments on commit ce5447a

Please sign in to comment.