-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
564 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// we abstract the login button component in case we need to change login | ||
// providers | ||
|
||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import { injectScript } from './common-client'; | ||
|
||
// LoginButton takes three properties: appId, onSuccess onFailure. | ||
// The latter two are callbacks used in the appropriate instances. | ||
// | ||
// ONSUCCESS is called with the appropriate ID token. | ||
// ONFAILURE is called with an error | ||
class GoogleLoginButton extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
// have we begun styling the button? | ||
isStyled: false, | ||
}; | ||
} | ||
|
||
// style the login button | ||
async styleButton() { | ||
if (!window.gapi) { | ||
await injectScript('https://apis.google.com/js/api.js'); | ||
} | ||
if (!window.gapi.signin2) { | ||
await new Promise( | ||
(resolveInner, rejectInner) => window.gapi.load('signin2', { | ||
callback: resolveInner, | ||
onerror: () => | ||
rejectInner(new Error('gapi.signin2 failed to load')), | ||
timeout: 5000, | ||
ontimeout: () => | ||
rejectInner(new Error('gapi.signin2 timed-out on load ')), | ||
})); | ||
} | ||
|
||
window.gapi.signin2.render('g-signin2', { | ||
id: 'g-signin2', | ||
onsuccess: (googleUser) => { | ||
this.props.onSuccess(googleUser.getAuthResponse().id_token); | ||
}, | ||
onfailure: this.props.onFailure, | ||
scope: 'email', | ||
}); | ||
} | ||
|
||
render(props) { | ||
if (!this.state.isStyled) { | ||
this.state.isStyled = true; | ||
|
||
this.styleButton(); | ||
|
||
// add a header with client id if not already present | ||
if (!document.querySelector('meta[name="google-signin-client_id"]')) { | ||
const meta = document.createElement('meta'); | ||
meta.name = 'google-signin-client_id'; | ||
meta.content = this.props.appId; | ||
document.head.appendChild(meta); | ||
} | ||
} | ||
return <div id="g-signin2" />; | ||
} | ||
} | ||
|
||
GoogleLoginButton.propTypes = { | ||
appId: PropTypes.string.isRequired, | ||
onSuccess: PropTypes.func, | ||
onFailure: PropTypes.func, | ||
}; | ||
|
||
GoogleLoginButton.defaultProps = { | ||
onSuccess: () => {}, | ||
onFailure: () => {}, | ||
}; | ||
|
||
export default GoogleLoginButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
import { deleteParseJson, printBackendError } from './common-client'; | ||
import googleLogOut from './googleLogOut'; | ||
|
||
class LogOutMain extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this._isMounted = true; | ||
this.state = { | ||
// an error message. null if we are waiting | ||
message: null, | ||
}; | ||
|
||
// note that we take a little care not to call setState after | ||
// component has unmounted | ||
deleteParseJson('/api/login') | ||
.then( | ||
async (response) => { | ||
if (!this._isMounted) return; | ||
if (response.error) { | ||
this.setState( | ||
{ message: printBackendError(response, true) }); | ||
} else { | ||
let isError = false; | ||
try { | ||
await googleLogOut(); | ||
if (!this._isMounted) return; | ||
} catch (e) { | ||
if (!this._isMounted) return; | ||
isError = true; | ||
this.setState( | ||
{ message: `Error logging out of Google:\n${e.message}` }); | ||
} | ||
if (!isError) window.location.href = '/'; | ||
} | ||
}, | ||
(e) => { | ||
if (!this._isMounted) return; | ||
this.setState({ message: e.message }); | ||
}); | ||
} | ||
|
||
componentWillUnmount() { | ||
this._isMounted = false; | ||
} | ||
|
||
render() { | ||
if (this.state.message) { | ||
return ( | ||
<h4 style={{ color: 'red' }}>{this.state.message}</h4> | ||
); | ||
} else { | ||
return ( | ||
<h1>Waiting on server response</h1> | ||
); | ||
} | ||
} | ||
} | ||
|
||
// this wrapper just takes care of recreating LogOutMain when component is | ||
// reloaded | ||
// eslint-disable-next-line react/no-multi-comp | ||
class LogOut extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { key: 0 }; | ||
this.props.history.listen((location, action) => { | ||
this.setState({ key: this.state.key + 1 }); | ||
}); | ||
} | ||
|
||
render() { | ||
return ( | ||
<LogOutMain | ||
key={this.state.key.toString()} | ||
/>); | ||
} | ||
} | ||
|
||
LogOut.propTypes = { | ||
// eslint-disable-next-line react/forbid-prop-types | ||
history: PropTypes.object.isRequired, | ||
}; | ||
|
||
export default LogOut; |
Oops, something went wrong.