diff --git a/README.md b/README.md index cc5679b..86a087e 100644 --- a/README.md +++ b/README.md @@ -24,16 +24,24 @@ Documentation for the project is hosted [here](https://osp-web-docs.surge.sh/). **Note:** Before setting up the frontend make sure to have Setup the [Backend Repo](https://github.com/anitab-org/open-source-programs-backend). -1. To start the server: +1. Create a `.env` file in the project root directory and add **Client ID** and **Callback URL** of GitHub App like this: + +``` +REACT_APP_GITHUB_CLIENT_ID=< GitHub App Client ID > +REACT_APP_GITHUB_CALLBACK_URL=< GitHub App Callback URL > +``` + +To get **Client ID** and **Callback URL** of GitHub App follow [this docs](https://docs.github.com/en/developers/apps/creating-a-github-app). + +2. To start the server: ``` -cd open-source-programs-web npm install npm start ``` -2. Navigate to `http://localhost:3000/` in your browser. -3. You can terminate the process by `Ctrl+C` in your terminal. +3. Navigate to `http://localhost:3000/` in your browser. +4. You can terminate the process by `Ctrl+C` in your terminal. ## Contributing diff --git a/package.json b/package.json index 0824938..2fe4589 100644 --- a/package.json +++ b/package.json @@ -7,16 +7,18 @@ "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "aws-sdk": "^2.734.0", - "axios": "^0.19.2", + "axios": "^0.21.1", "dotenv": "^8.2.0", + "github-login": "^1.0.12", "moment": "^2.27.0", "prop-types": "^15.7.2", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-github-login": "^1.0.3", "react-redux": "^7.2.0", "react-router-dom": "^5.2.0", "react-router-redux": "^4.0.8", - "react-scripts": "3.4.1", + "react-scripts": "^4.0.3", "redux": "^4.0.5", "redux-api-middleware": "^3.2.1", "redux-persist": "^6.0.0", diff --git a/src/actions/login.js b/src/actions/login.js index c2edb5c..b2e6e36 100644 --- a/src/actions/login.js +++ b/src/actions/login.js @@ -1,5 +1,5 @@ import axios from 'axios'; -import { urlLogin, urlRegister } from '../urls'; +import { urlLogin, urlRegister, urlGithubLogin } from '../urls'; import { LOGIN, REGISTER, LOGIN_ERRORS, REGISTER_ERRORS } from './types'; export const postLogin = (data, callback) => async (dispatch) => { @@ -48,3 +48,27 @@ export const postRegister = (data, callback) => async (dispatch) => { callback(); } }; + +export const postGithubCode = (data, callback) => async (dispatch) => { + try { + const config = { + headers: { + 'content-type': 'application/json', + }, + }; + const res = await axios.post(urlGithubLogin(), data, config); + dispatch({ + type: LOGIN, + payload: res.data, + }); + + localStorage.setItem('token', res.data.access_token); + callback(); + } catch (err) { + dispatch({ + type: LOGIN_ERRORS, + payload: err.response, + }); + callback(); + } +}; diff --git a/src/components/GitHubAuth.js b/src/components/GitHubAuth.js new file mode 100644 index 0000000..8627799 --- /dev/null +++ b/src/components/GitHubAuth.js @@ -0,0 +1,131 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import GitHubLogin from 'react-github-login'; +import { postGithubCode } from '../actions/login'; +import { withRouter } from 'react-router'; +import { Icon, Message } from 'semantic-ui-react'; + +class GitHubAuth extends Component { + constructor(props) { + super(props); + this.state = { + code: '', + error: null, + posted: false, + errorText: '', + }; + this.postCode = this.postCode.bind(this); + this.GithubError = this.GithubError.bind(this); + } + + postCode = (response) => { + console.log(response.code); + this.setState({ + code: response.code, + }); + const data = { + code: this.state.code, + }; + this.props.postGithubCode(data, this.callback); + this.setState({ + code: '', + }); + }; + + callback = () => { + this.setState({ + error: this.props.loginerror ? true : false, + posted: true, + errorText: 'Server Error: try again.', + }); + console.log(this.state.error, this.state.posted); + if (!this.state.error) { + this.props.history.push('/'); + } + setTimeout(() => { + this.setState({ + error: false, + posted: false, + }); + }, 4000); + }; + + icon = () => { + return ( + + Log in with GitHub + + ); + }; + + GithubError = (response) => { + console.log(response); + this.setState({ + error: true, + posted: true, + errorText: 'GitHub API Error.', + }); + setTimeout(() => { + this.setState({ + error: false, + posted: false, + }); + }, 4000); + }; + + UNSAFE_componentWillMount() { + this.setState({ + code: '', + error: null, + posted: false, + errorText: '', + }); + } + + componentWillUnmount() { + // eslint-disable-next-line + this.setState = (state, callback) => { + return; + }; + } + + render() { + const { + REACT_APP_GITHUB_CLIENT_ID, + REACT_APP_GITHUB_CALLBACK_URL, + } = process.env; + const { error, posted, errorText } = this.state; + const onFailure = (response) => this.GithubError(response); + return ( + <> + {error && posted ? ( + + ) : ( + + {this.icon()} + + )} + + ); + } +} + +GitHubAuth.propTypes = { + postGithubCode: PropTypes.func.isRequired, +}; + +const mapStateToProps = (state) => ({ + login: state.login.login, + loginerror: state.login.loginerror, +}); + +export default connect(mapStateToProps, { postGithubCode })( + withRouter(GitHubAuth) +); diff --git a/src/components/Login.js b/src/components/Login.js index 4884f45..1d255a3 100644 --- a/src/components/Login.js +++ b/src/components/Login.js @@ -10,11 +10,13 @@ import { Icon, Message, Button, + Segment, } from 'semantic-ui-react'; import PropTypes from 'prop-types'; import './../styles/Login.css'; import orgLogo from '../assets/org-logo.jpg'; import { register } from '../urls'; +import GitHubAuth from './GitHubAuth'; class Login extends Component { constructor(props) { @@ -168,6 +170,9 @@ class Login extends Component { ) : null} + + + Don't have an account?{' '} Register here. diff --git a/src/urls.js b/src/urls.js index 6831eec..f75c1c3 100644 --- a/src/urls.js +++ b/src/urls.js @@ -47,6 +47,10 @@ export function urlRegister() { return `${urlBaseBackend()}/token_auth/register/`; } +export function urlGithubLogin() { + return `${urlBaseBackend()}/token_auth/github/`; +} + export function urlInfo() { return `${urlBaseBackend()}/info/`; }