diff --git a/README.md b/README.md index fc1ed0e..6221aec 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,27 @@ See Guild https://github.com/lorenwest/node-config/wiki/Configuration-Files |`PORT`| The port to listen| |`GOOGLE_API_KEY`| The google api key see (https://developers.google.com/maps/documentation/javascript/get-api-key#key)| |`API_BASE_URL`| The base URL for Drone API | - +|`REACT_APP_AUTH0_CLIENT_ID`| The auth0 client id | +|`REACT_APP_AUTH0_CLIENT_DOMAIN`| The auth0 client domain | + +### Auth0 setup +- Create an account on auth0. +- Click on clients in left side menu, it will redirect you to client page. Click on CREATE CLIENT button + to create a new client. +- Copy the client id and client domain and export them as environment variables. +- Add `http://localhost:3000` as Allowed callback url's in client settings. + +### Add social connections + +### Facebook social connection +- To add facebook social connection to auth0, you have to create a facebook app. + Go to facebook [developers](https://developers.facebook.com/apps) and create a new app. +- Copy the app secret and app id to auth0 social connections facebook tab. +- You have to setup the oauth2 callback in app oauth settings. +- For more information visit auth0 [docs](https://auth0.com/docs/connections/social/facebook) + +### Google social connection +- For more information on how to connect google oauth2 client, visit official [docs](https://auth0.com/docs/connections/social/google) ## Install dependencies `npm i` diff --git a/config/default.js b/config/default.js index 6bc8230..d35b608 100644 --- a/config/default.js +++ b/config/default.js @@ -1,6 +1,6 @@ /* eslint-disable import/no-commonjs */ /** - * Main config file + * Main config file for the server which is hosting the reat app */ module.exports = { // below env variables are NOT visible in frontend @@ -8,5 +8,4 @@ module.exports = { // below env variables are visible in frontend GOOGLE_API_KEY: process.env.GOOGLE_API_KEY || 'AIzaSyCrL-O319wNJK8kk8J_JAYsWgu6yo5YsDI', - API_BASE_PATH: process.env.API_BASE_PATH || 'https://kb-dsp-server-dev.herokuapp.com', }; diff --git a/envSample b/envSample index 4a42b68..003a7ca 100644 --- a/envSample +++ b/envSample @@ -1,5 +1,5 @@ -REACT_APP_API_BASE_PATH=https://kb-dsp-server.herokuapp.com -REACT_APP_SOCKET_URL=https://kb-dsp-server.herokuapp.com -REACT_APP_AUTH0_CLIEND_ID=3CGKzjS2nVSqHxHHE64RhvvKY6e0TYpK -REACT_APP_AUTH0_DOMAIN=dronetest.auth0.com -REACT_APP_GOOGLE_API_KEY=AIzaSyCR3jfBdv9prCBYBOf-fPUDhjPP4K05YjE +GOOGLE_API_KEY=AIzaSyCrL-O319wNJK8kk8J_JAYsWgu6yo5YsDI +API_BASE_PATH=http://localhost:3500 +REACT_APP_AUTH0_CLIENT_ID=h7p6V93Shau3SSvqGrl6V4xrATlkrVGm +REACT_APP_AUTH0_CLIENT_DOMAIN=spanhawk.auth0.com +REACT_APP_SOCKET_URL=http://localhost:3500 \ No newline at end of file diff --git a/package.json b/package.json index 2ee9179..56a0a6a 100644 --- a/package.json +++ b/package.json @@ -55,18 +55,18 @@ "rc-tooltip": "^3.4.2", "react": "^15.3.2", "react-breadcrumbs": "^1.5.1", - "react-count-down": "^1.0.3", "react-click-outside": "^2.2.0", + "react-count-down": "^1.0.3", "react-css-modules": "^3.7.10", "react-date-picker": "^5.3.28", "react-dom": "^15.3.2", + "react-dropdown": "^1.2.0", "react-flexbox-grid": "^0.10.2", "react-google-maps": "^6.0.1", - "react-modal": "^1.5.2", - "react-dropdown": "^1.2.0", + "react-highcharts": "^11.0.0", "react-icheck": "^0.3.6", "react-input-range": "^0.9.3", - "react-highcharts": "^11.0.0", + "react-modal": "^1.5.2", "react-redux": "^4.0.0", "react-redux-toastr": "^4.2.2", "react-router": "^2.8.1", @@ -75,8 +75,8 @@ "react-simple-dropdown": "^1.1.5", "react-slick": "^0.14.5", "react-star-rating-component": "^1.2.2", - "react-timeago": "^3.1.3", "react-tabs": "^0.8.2", + "react-timeago": "^3.1.3", "reactable": "^0.14.1", "redbox-react": "^1.2.10", "redux": "^3.0.0", @@ -86,8 +86,8 @@ "redux-logger": "^2.6.1", "redux-thunk": "^2.0.0", "sass-loader": "^4.0.0", - "socket.io-client": "^1.7.1", "slick-carousel": "^1.6.0", + "socket.io-client": "^1.7.1", "style-loader": "^0.13.0", "superagent": "^2.3.0", "superagent-promise": "^1.1.0", diff --git a/src/api/User.js b/src/api/User.js index 70c1728..a12bc57 100644 --- a/src/api/User.js +++ b/src/api/User.js @@ -56,7 +56,7 @@ class UserApi { })}); } - registerSocialUser(name, email) { + registerSocialUser(name, email, token) { const url = `${this.basePath}/api/v1/login/social`; return reqwest({ @@ -64,6 +64,9 @@ class UserApi { method: 'post', type: 'json', contentType: 'application/json', + headers: { + Authorization: `Bearer ${token}`, + }, data: JSON.stringify({ name, email, diff --git a/src/components/TextField/TextField.scss b/src/components/TextField/TextField.scss index 46a04ab..56f5f52 100644 --- a/src/components/TextField/TextField.scss +++ b/src/components/TextField/TextField.scss @@ -2,6 +2,7 @@ width: 100%; border: 1px solid #ebebeb; + input[type="password"], input[type="text"] { width: 100%; padding: 0 10px; diff --git a/src/config/index.js b/src/config/index.js index c6b575d..db5b4f9 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -1,23 +1,14 @@ +/* eslint-disable import/no-commonjs */ /** - * Copyright (c) 2016 Topcoder Inc, All rights reserved. + * Main config file for the react app */ - -/** - * Webapp configuration - * - * @author TCSCODER - * @version 1.0.0 - */ - -const config = { - api: { - basePath: process.env.REACT_APP_API_BASE_PATH || 'http://localhost:3500', - }, +module.exports = { + // below env variables are visible in frontend + API_BASE_PATH: process.env.API_BASE_PATH || 'http://localhost:3500', + REACT_APP_AUTH0_CLIENT_ID: process.env.REACT_APP_AUTH0_CLIENT_ID || 'h7p6V93Shau3SSvqGrl6V4xrATlkrVGm', + REACT_APP_AUTH0_CLIENT_DOMAIN: process.env.REACT_APP_AUTH0_CLIENT_DOMAIN || 'spanhawk.auth0.com', + AUTH0_CALLBACK: 'http://localhost:3000', socket: { url: process.env.REACT_APP_SOCKET_URL || 'http://localhost:3500', }, - AUTH0_CLIEND_ID: process.env.REACT_APP_AUTH0_CLIEND_ID || '3CGKzjS2nVSqHxHHE64RhvvKY6e0TYpK', - AUTH0_DOMAIN: process.env.REACT_APP_AUTH0_DOMAIN || 'dronetest.auth0.com', }; - -export default config; diff --git a/src/routes/DronesMap/modules/DronesMap.js b/src/routes/DronesMap/modules/DronesMap.js index 71ac81b..eb8da53 100644 --- a/src/routes/DronesMap/modules/DronesMap.js +++ b/src/routes/DronesMap/modules/DronesMap.js @@ -1,7 +1,7 @@ import {handleActions} from 'redux-actions'; import io from 'socket.io-client'; import APIService from 'services/APIService'; -import config from '../../../../config/default'; +import config from '../../../config'; // Drones will be updated and map will be redrawn every 3s // Otherwise if drones are updated with high frequency (e.g. 0.5s), the map will be freezing @@ -32,7 +32,7 @@ export const init = () => async(dispatch) => { const {body: {items: drones}} = await APIService.searchDrones({limit: DRONE_LIMIT}); lastUpdated = new Date().getTime(); dispatch({type: DRONES_LOADED, payload: {drones}}); - socket = io(config.API_BASE_PATH); + socket = io(config.socket.url); socket.on('dronepositionupdate', (drone) => { pendingUpdates[drone.id] = drone; if (updateTimeoutId) { diff --git a/src/routes/Home/components/LoginModal/LoginModal.jsx b/src/routes/Home/components/LoginModal/LoginModal.jsx index 5bd807e..2ed19ff 100644 --- a/src/routes/Home/components/LoginModal/LoginModal.jsx +++ b/src/routes/Home/components/LoginModal/LoginModal.jsx @@ -7,6 +7,12 @@ import Button from 'components/Button'; import Checkbox from 'components/Checkbox'; import TextField from 'components/TextField'; import styles from './LoginModal.scss'; +import APIService from '../../../../services/APIService'; +import {toastr} from 'react-redux-toastr'; +import {defaultAuth0Service} from '../../../../services/AuthService'; + +const EMAIL_REGEX = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i; + /* * customStyles */ @@ -50,10 +56,11 @@ FormField.propTypes = { */ class LogInModal extends React.Component { - constructor() { - super(); + constructor(props) { + super(props); this.state = { modalLoginIsOpen: false, + showForgetPassword: false, }; } @@ -62,7 +69,7 @@ class LogInModal extends React.Component { } closeLoginModal() { - this.setState({modalLoginIsOpen: false}); + this.setState({modalLoginIsOpen: false, showForgetPassword: false}); } login() { @@ -70,7 +77,6 @@ class LogInModal extends React.Component { } handleLogin(handleLoggedIn, loggedUser) { - handleLoggedIn(); const _self = this; setTimeout(() => { handleLoggedIn(); @@ -81,9 +87,53 @@ class LogInModal extends React.Component { }, 100); } + forgetPassword() { + this.setState({showForgetPassword: true}); + } + + /** + * Login using google social network, + * this method internally uses auth0 service + */ + googleLogin() { + defaultAuth0Service.login({connection: 'google-oauth2'}, (error) => { + if (error) { + const message = error.message || 'something went wrong, please try again'; + toastr.error(message); + } + }); + } + + /** + * Login using facebook social network, + * this method internally uses auth0 service + */ + facebookLogin() { + defaultAuth0Service.login({connection: 'facebook'}, (error) => { + if (error) { + const message = error.message || 'something went wrong, please try again'; + toastr.error(message); + } + }); + } + + /** + * This method is invoked when reset password request is submitted + */ + handleForgetPassword(data) { + APIService.forgotPassword({email: data.emailUp}).then(() => { + toastr.success('', 'Reset password link emailed to your email address'); + this.closeLoginModal(); + }).catch((reason) => { + const message = reason.response.body.error || 'something went wrong, please try again'; + toastr.error(message); + this.closeLoginModal(); + }); + } + render() { + const _self = this; const {handleSubmit, fields, handleLoggedIn, loggedUser, hasError, errorText} = this.props; - return (