Skip to content

Commit

Permalink
Store authentication details in Redux.
Browse files Browse the repository at this point in the history
  • Loading branch information
roelfie committed Jan 7, 2021
1 parent 3ff2240 commit c38adf4
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 22 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,11 @@ Setup an OAuth 2.0 project in the [Google API Console](https://console.developer
- [API Reference](https://developers.google.com/identity/sign-in/web/reference)
- [Github](https://github.com/google/google-api-javascript-client)
### Examples
- [Google Authentication](https://github.com/roelfie/react-redux-udemy/commit/3ff22400d13c093ebd71b005b940614e05c9ff8c) (login status stored in component state)
- [Google Authentication with Redux](???)
# Appendix: JavaScript
### Named vs. default exports
Expand Down
26 changes: 26 additions & 0 deletions streams/client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions streams/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
"@testing-library/user-event": "^12.6.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.1",
"redux": "^4.0.5",
"web-vitals": "^0.2.4"
},
"scripts": {
Expand Down
21 changes: 21 additions & 0 deletions streams/client/src/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { SIGN_IN, SIGN_OUT } from "./types";

// https://developers.google.com/identity/sign-in/web/reference#users
export const registerLogin = (googleUser) => {
const profile = googleUser.getBasicProfile();
return {
type: SIGN_IN,
payload: {
userid: profile.getId(),
username: profile.getName(),
email: profile.getEmail()
}
};
};

export const registerLogout = () => {
return {
type: SIGN_OUT,
payload: {}
};
};
2 changes: 2 additions & 0 deletions streams/client/src/actions/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const SIGN_IN = "SIGN_IN";
export const SIGN_OUT = "SIGN_OUT";
51 changes: 30 additions & 21 deletions streams/client/src/components/GoogleAuthenticator.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from "react";
import { connect } from "react-redux";

import GoogleButton from "./GoogleButton";
import { registerLogin, registerLogout } from "../actions";

const CLIENT_ID = "MY_CLIENT_ID.apps.googleusercontent.com";

class GoogleAuthenticator extends React.Component {
state = { isSignedIn: null };

componentDidMount() {
window.gapi.load("client:auth2", () => {
window.gapi.client
Expand All @@ -13,41 +15,48 @@ class GoogleAuthenticator extends React.Component {
scope: "email"
})
.then(() => {
// https://developers.google.com/identity/sign-in/web/reference
this.GoogleAuth = window.gapi.auth2.getAuthInstance();
this.setState({ isSignedIn: this.GoogleAuth.isSignedIn.get() });
// https://developers.google.com/identity/sign-in/web/reference#googleauthissignedinlistenlistener
this.GoogleAuth.isSignedIn.listen(this.onAuthChanged);
this.onAuthChanged(this.GoogleAuth.isSignedIn.get());
});
});
}

onAuthChanged = () => {
this.setState({ isSignedIn: this.GoogleAuth.isSignedIn.get() });
onAuthChanged = (isSignedIn) => {
if (isSignedIn) {
this.props.registerLogin(this.GoogleAuth.currentUser.get());
} else {
this.props.registerLogout();
}
};

renderButtons() {
if (this.state.isSignedIn === null) {
renderButtons = () => {
if (this.props.isSignedIn === null) {
return null;
}
if (this.state.isSignedIn) {
if (this.props.isSignedIn) {
return (
<button className='ui red google button' onClick={this.GoogleAuth.signOut}>
<i className='google icon'></i>
Sign Out
</button>
<GoogleButton
color='red'
onClick={() => this.GoogleAuth.signOut()}
label={`Sign Out (${this.props.username})`}
/>
);
}
return (
<button className='ui blue google button' onClick={this.GoogleAuth.signIn}>
<i className='google icon'></i>
Sign In with Google
</button>
);
}
return <GoogleButton onClick={() => this.GoogleAuth.signIn()} label='Sign In with Google' />;
};

render() {
return <div>{this.renderButtons()}</div>;
}
}

export default GoogleAuthenticator;
const mapStateToProps = (state) => {
return {
isSignedIn: state.authDetails.isSignedIn,
username: state.authDetails.username
};
};

export default connect(mapStateToProps, { registerLogin, registerLogout })(GoogleAuthenticator);
12 changes: 12 additions & 0 deletions streams/client/src/components/GoogleButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react";

const GoogleButton = ({ color = "blue", onClick, label }) => {
return (
<button className={`ui ${color} google button`} onClick={onClick}>
<i className='google icon'></i>
{label}
</button>
);
};

export default GoogleButton;
13 changes: 12 additions & 1 deletion streams/client/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";

import App from "./components/App";
import reducers from "./reducers";

const store = createStore(reducers);

ReactDOM.render(<App />, document.getElementById("root"));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
27 changes: 27 additions & 0 deletions streams/client/src/reducers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { combineReducers } from "redux";
import { SIGN_IN, SIGN_OUT } from "../actions/types";

const SIGNED_OUT_STATE = {
isSignedIn: false,
userid: null,
username: null,
email: null
};

const authenticationReducer = (state = SIGNED_OUT_STATE, action) => {
switch (action.type) {
case SIGN_IN:
return {
isSignedIn: true,
userid: action.payload.userid,
username: action.payload.username,
email: action.payload.email
};
case SIGN_OUT:
return SIGNED_OUT_STATE;
default:
return state;
}
};

export default combineReducers({ authDetails: authenticationReducer });

0 comments on commit c38adf4

Please sign in to comment.