diff --git a/.github/workflows/qa-checks.yml b/.github/workflows/qa-checks.yml
index f69022a..fc638d5 100644
--- a/.github/workflows/qa-checks.yml
+++ b/.github/workflows/qa-checks.yml
@@ -21,9 +21,6 @@ jobs:
run: npm install
- name: Linters and Formatters Check
- uses: wearerequired/lint-action@v1
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- # Enable linters
- eslint: true
- prettier: true
+ run: |
+ npm run lint
+ npm run check
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..d0ff220 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",
@@ -33,7 +35,8 @@
"eject": "react-scripts eject",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
- "format": "prettier --write \"**/*.+(js|jsx|json|css|md)\""
+ "format": "prettier --write \"**/*.+(js|jsx|json|css|md)\"",
+ "check": "prettier -c \"**/*.+(js|jsx|json|css|md)\""
},
"browserslist": {
"production": [
diff --git a/src/App.test.js b/src/App.test.js
deleted file mode 100644
index 4db7ebc..0000000
--- a/src/App.test.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from 'react';
-import { render } from '@testing-library/react';
-import App from './App';
-
-test('renders learn react link', () => {
- const { getByText } = render();
- const linkElement = getByText(/learn react/i);
- expect(linkElement).toBeInTheDocument();
-});
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..d4e33bc
--- /dev/null
+++ b/src/components/GitHubAuth.js
@@ -0,0 +1,128 @@
+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 { 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) => {
+ 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.',
+ });
+ if (!this.state.error) {
+ this.props.history.push('/');
+ }
+ setTimeout(() => {
+ this.setState({
+ error: false,
+ posted: false,
+ });
+ }, 4000);
+ };
+
+ githubIcon = () => {
+ 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);
+ };
+
+ componentDidMount() {
+ 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.githubIcon()}
+
+ )}
+ >
+ );
+ }
+}
+
+GitHubAuth.propTypes = {
+ postGithubCode: PropTypes.func.isRequired,
+};
+
+const mapStateToProps = (state) => ({
+ login: state.login.login,
+ loginerror: state.login.loginerror,
+});
+
+export default connect(mapStateToProps, { postGithubCode })(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/tests/GitHubAuth.test.js b/src/tests/GitHubAuth.test.js
new file mode 100644
index 0000000..ce10ae0
--- /dev/null
+++ b/src/tests/GitHubAuth.test.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import { createStore } from 'redux';
+import { Provider } from 'react-redux';
+import { render, cleanup } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import GitHubAuth from '../components/GitHubAuth';
+import loginReducer from '../reducers/login';
+
+afterEach(cleanup);
+
+function renderWithRedux(
+ component,
+ { initialState, store = createStore(loginReducer, initialState) } = {}
+) {
+ return {
+ ...render({component}),
+ };
+}
+
+it('Renders GitHub Login Button', () => {
+ const { getByTestId } = renderWithRedux();
+ expect(getByTestId('GitHubLoginButton')).toHaveTextContent(
+ 'Log in with GitHub'
+ );
+});
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/`;
}