Skip to content

Commit

Permalink
feat(social-auth): social-authentication using google and facebook
Browse files Browse the repository at this point in the history
- install react-facebook-login and react-google-login modules
- create a social authentication component
- create actions for the social authentication component
- create a reducer for the social authentication component
- add the route to the component
- add backend api urls to the config.json file
- add tests for socialauth functionality
- put test folder into src
- refactor jest.config.js
- install moxios and react-mock for testing

[Finishes #164798254]
  • Loading branch information
Kisekka David authored and Kisekka David committed May 14, 2019
1 parent 29749e4 commit 95cab99
Show file tree
Hide file tree
Showing 23 changed files with 1,286 additions and 50 deletions.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"test": "jest -u --coverage",
"test:watch": "jest --watch",
"test:coveralls": "jest --coverage --coverageReporters=text-lcov | coveralls",
"start": "webpack-dev-server --open --hot --mode development",
"start": "webpack-dev-server --open --hot --mode development --https",
"build": "webpack --mode production",
"lint": "eslint . --ignore-path .eslintignore",
"lint:fix": "eslint . --ignore-path .gitignore --fix"
Expand All @@ -36,6 +36,8 @@
"express": "^4.16.4",
"moment": "^2.24.0",
"moxios": "^0.4.0",
"react-facebook-login": "^4.1.1",
"react-google-login": "^5.0.4",
"react-loader": "^2.4.5",
"react-redux": "^7.0.3",
"react-router-dom": "^5.0.0",
Expand Down Expand Up @@ -66,6 +68,7 @@
"react": "^16.8.6",
"react-dom": "^16.8.6",
"redux-devtools-extension": "^2.13.8",
"redux-mock-store": "^1.5.3",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"webpack": "^4.30.0",
Expand Down
96 changes: 96 additions & 0 deletions src/actions/SocialAuthActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import endpoints from "../urls";
import {
GOOGLE_FAILURE,
GOOGLE_LOGIN,
FACEBOOK_FAILURE,
FACEBOOK_LOGIN
} from "./types";
import axios from "axios";
import "react-toastify/dist/ReactToastify.css";
import { toast } from "react-toastify";

export const facebooklogin = token => dispatch => {
const body = {
user_token: {
auth_token: token
}
};

const headers = {
"Content-Type": "application/json"
};
return axios
.post(endpoints.facebookLogin, body, { headers: headers })
.then(data => {
if (data.data.errors) {
dispatch({
type: FACEBOOK_FAILURE,
payload: data.data
});
} else {
if (data.data["auth_token"].username) {
toast.success(
`Welcome ${data.data["auth_token"].username}. Login Successful`,
{
position: toast.POSITION.TOP_RIGHT,
autoClose: 5000,
hideProgressBar: false
}
);
dispatch({
type: FACEBOOK_LOGIN,
payload: data.data["auth_token"]
});
} else {
toast.success(`${data.data["auth_token"]}`, {
position: toast.POSITION.TOP_RIGHT,
autoClose: 5000,
hideProgressBar: false
});
}
}
});
};

export const googlelogin = token => dispatch => {
const body = {
user_token: {
auth_token: token
}
};

const headers = {
"Content-Type": "application/json"
};
return axios
.post(endpoints.googleLogin, body, { headers: headers })
.then(data => {
if (data.data.errors) {
dispatch({
type: GOOGLE_FAILURE,
payload: data.data
});
} else {
if (data.data["auth_token"].username) {
toast.success(
`Welcome ${data.data["auth_token"].username}. Login Successful`,
{
position: toast.POSITION.TOP_RIGHT,
autoClose: 5000,
hideProgressBar: false
}
);
dispatch({
type: GOOGLE_LOGIN,
payload: data.data["auth_token"]
});
} else {
toast.success(`${data.data["auth_token"]}`, {
position: toast.POSITION.TOP_RIGHT,
autoClose: 5000,
hideProgressBar: false
});
}
}
});
};
4 changes: 4 additions & 0 deletions src/actions/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ export const FETCH_ARTICLES_SUCCESS = "FETCH_ARTICLES_SUCCESS";
export const LOGIN_STARTED = "LOGIN_STARTED";
export const LOGIN_FAIL = "LOGIN_FAIL";
export const SUCCESSFUL = "SUCCESSFUL";
export const GOOGLE_LOGIN = "GOOGLE_LOGIN";
export const GOOGLE_FAILURE = "GOOGLE_FAILURE";
export const FACEBOOK_LOGIN = "FACEBOOK_LOGIN";
export const FACEBOOK_FAILURE = "FACEBOOK_FAILURE";
37 changes: 37 additions & 0 deletions src/components/SocialAuth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from "react";
import FacebookLogin from "react-facebook-login";
import GoogleLogin from "react-google-login";
import config from "../../src/config.json";
import color from "@material-ui/core/colors/grey";

export const SocialAuth = props => (
<div>
<div className="face-book">
<FacebookLogin
appId={config.appId}
fields="name,email,picture"
callback={props.facebooksuccess}
icon={
<img
src="https://img.icons8.com/color/96/000000/facebook.png"
width="=40px"
height="40px"
alt="facebook"
/>
}
textButton="SIGN IN WITH FACEBOOK"
/>
</div>
<br />
<div className="google">
<GoogleLogin
clientId={config.clientId}
buttonText="SIGN IN WITH GOOGLE"
onSuccess={props.googlesuccess}
onFailure={props.googlefailure}
/>
</div>
</div>
);

export default SocialAuth;
30 changes: 2 additions & 28 deletions src/components/login/LoginModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { withStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import Button from "@material-ui/core/Button";
import "../../styles/register.scss";
import SocialAuthContainer from "../../containers/SocialAuthContainer";

const styles = themes => ({
floatingLabelFocusStyle: {
Expand Down Expand Up @@ -41,33 +42,7 @@ const LoginComponent = props => {
<Grid container spacing={24}>
<Grid item lg={6} md={6}>
<div className="button-collective">
<Button className="face-book">
<img
src="https://img.icons8.com/color/96/000000/facebook.png"
width="=40px"
height="40px"
alt="facebook"
/>
Login with Facebook
</Button>
<Button className="twitter">
<img
src="https://img.icons8.com/color/96/000000/twitter-circled.png"
width="=40px"
height="40px"
alt="twitter"
/>
Login with Twitter
</Button>
<Button className="google">
<img
src="https://img.icons8.com/color/96/000000/google-logo.png"
width="=40px"
height="40px"
alt="google"
/>
Login with Google
</Button>
<SocialAuthContainer />
</div>
</Grid>
<Grid
Expand Down Expand Up @@ -107,7 +82,6 @@ const LoginComponent = props => {
value={password}
onChange={handleChange}
/>

<Loader loaded={!isProcessing} />
<Button type="submit" className="button-success">
Login
Expand Down
10 changes: 7 additions & 3 deletions src/components/routes.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import React, { Component } from "react";
import { BrowserRouter, Route } from "react-router-dom";
import LoginContainer from "../containers/Login/LoginContainer";
import SocialAuthContainer from "../containers/SocialAuthContainer";
import Home from "./home";

class Routes extends Component {
render() {
return (
<BrowserRouter>
<Route exact path="/" component={Home} />
<Route exact path="/home" component={Home} />
<Route path="/login" component={LoginContainer} />
<div>
<Route exact path="/" component={Home} />
<Route exact path="/home" component={Home} />
<Route path="/login" component={LoginContainer} />
<Route path="/socialAuth" component={SocialAuthContainer} />
</div>
</BrowserRouter>
);
}
Expand Down
4 changes: 4 additions & 0 deletions src/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"appId": 281662639446583,
"clientId": "140929687593-ul95834mce97cv333q6ci5i78rnmhu87.apps.googleusercontent.com"
}
60 changes: 60 additions & 0 deletions src/containers/SocialAuthContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, { Component } from "react";
import { connect } from "react-redux";
import { facebooklogin, googlelogin } from "../actions/SocialAuthActions";
import { SocialAuth } from "../components/SocialAuth";
import { toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { withRouter } from "react-router-dom";

export class SocialAuthContainer extends Component {
constructor(props) {
super(props);
}
componentWillReceiveProps(nextProps) {
if (nextProps.socialAuthState.isAuthenticated) {
localStorage.setItem("token", nextProps.socialAuthState.payload);
this.props.history.push("/");
}
}

handlefacebooksuccess = response => {
const { facebooklogin } = this.props;
if (response.accessToken) {
facebooklogin(response.accessToken);
}
};
handlegooglesuccess = response => {
const { googlelogin } = this.props;
if (response.tokenId) {
googlelogin(response.tokenId);
}
};
handlegooglefailure = response => {
const { googlelogin } = this.props;
googlelogin("invalid request");
};

render() {
return (
<div>
<SocialAuth
id="socialAuth"
facebooksuccess={this.handlefacebooksuccess}
googlesuccess={this.handlegooglesuccess}
googlefailure={this.handlegooglefailure}
/>
</div>
);
}
}

export const mapStateToProps = state => ({
socialAuthState: state.socialAuthReducer
});

export default withRouter(
connect(
mapStateToProps,
{ facebooklogin, googlelogin }
)(SocialAuthContainer)
);
2 changes: 1 addition & 1 deletion src/containers/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { Provider } from "react-redux";
import store from "../store";
import "../styles/app.scss";
import "react-toastify/dist/ReactToastify.css";
import { ToastContainer } from "react-toastify";
import Routes from "../components/routes";
import { ToastContainer } from "react-toastify";

class App extends Component {
render() {
Expand Down
2 changes: 2 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<link
href="https://fonts.googleapis.com/css?family=Quantico"
rel="stylesheet"
/>

<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Authors's haven</title>
</head>
Expand Down
4 changes: 3 additions & 1 deletion src/reducers/rootReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { combineReducers } from "redux";
import authReducer from "./authReducer";
import loginReducer from "./loginReducer";
import getArticlesReducer from "./getArticlesReducer";
import socialAuthReducer from "./socialAuthReducer";

export default combineReducers({
auth_login: loginReducer,
getArticlesReducer
getArticlesReducer,
socialAuthReducer: socialAuthReducer
});
49 changes: 49 additions & 0 deletions src/reducers/socialAuthReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
GOOGLE_FAILURE,
GOOGLE_LOGIN,
FACEBOOK_FAILURE,
FACEBOOK_LOGIN
} from "../actions/types";

const initialState = {
isAuthenticated: false,
facebook_login: false,
google_login: false,
payload: "",
token: ""
};

const socialAuthReducer = (state = initialState, action) => {
switch (action.type) {
case FACEBOOK_LOGIN:
return {
...state,
isAuthenticated: true,
facebook_login: true,
token: action.token,
payload: action.payload
};
case FACEBOOK_FAILURE:
return {
...state,
payload: action.payload
};
case GOOGLE_LOGIN:
return {
...state,
isAuthenticated: true,
google_login: true,
token: action.token,
payload: action.payload
};
case GOOGLE_FAILURE:
return {
...state,
payload: action.payload
};
default:
return state;
}
};

export default socialAuthReducer;
Loading

0 comments on commit 95cab99

Please sign in to comment.