From dcd03d78885620c12b2f6c20c211a610a5de7668 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Wed, 2 Oct 2019 00:49:51 -0400 Subject: [PATCH 1/5] Login frontend complete --- functions/handlers/users.js | 4 +- twistter-frontend/package-lock.json | 5 + twistter-frontend/package.json | 3 +- twistter-frontend/src/App.js | 25 +++- twistter-frontend/src/pages/Login.js | 187 +++++++++++++++++++++--- twistter-frontend/src/util/AuthRoute.js | 11 ++ 6 files changed, 206 insertions(+), 29 deletions(-) create mode 100644 twistter-frontend/src/util/AuthRoute.js diff --git a/functions/handlers/users.js b/functions/handlers/users.js index cdeb3f6..1c217e5 100644 --- a/functions/handlers/users.js +++ b/functions/handlers/users.js @@ -121,11 +121,11 @@ exports.login = (req, res) => { return data.user.getIdToken(); }) .then((token) => { - return res.json({ token }); + return res.status(200).json({ token }); }) .catch((err) => { console.error(err); - if (err.code === "auth/wrong-password") { + if (err.code === "auth/wrong-password" || err.code === "auth/invalid-email") { return res .status(403) .json({ general: "Invalid credentials. Please try again." }); diff --git a/twistter-frontend/package-lock.json b/twistter-frontend/package-lock.json index 2fb6aa4..8b43be3 100644 --- a/twistter-frontend/package-lock.json +++ b/twistter-frontend/package-lock.json @@ -5277,6 +5277,11 @@ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=" }, + "jwt-decode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz", + "integrity": "sha1-fYa9VmefWM5qhHBKZX3TkruoGnk=" + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", diff --git a/twistter-frontend/package.json b/twistter-frontend/package.json index bc4672f..a83c175 100644 --- a/twistter-frontend/package.json +++ b/twistter-frontend/package.json @@ -8,6 +8,7 @@ "clsx": "^1.0.4", "create-react-app": "^3.1.2", "install": "^0.13.0", + "jwt-decode": "^2.2.0", "node-pre-gyp": "^0.13.0", "react": "^16.9.0", "react-dom": "^16.9.0", @@ -36,5 +37,5 @@ "last 1 safari version" ] }, - "proxy": "https://us-central1-twistter-e4649.cloudfunctions.net/api" + "proxy": "https://us-central1-twistter-e4649.cloudfunctions.net/api" } diff --git a/twistter-frontend/src/App.js b/twistter-frontend/src/App.js index a0a4720..4a13d53 100644 --- a/twistter-frontend/src/App.js +++ b/twistter-frontend/src/App.js @@ -6,16 +6,31 @@ import './App.css'; import { BrowserRouter as Router } from 'react-router-dom'; import Route from 'react-router-dom/Route'; import Navbar from './components/layout/NavBar'; +import jwtDecode from 'jwt-decode'; + +// Components +import AuthRoute from './util/AuthRoute'; import home from './pages/Home'; import register from './pages/Register'; import login from './pages/Login'; -import user from './pages/User'; - +import user from './pages/user'; import writeMicroblog from './Writing_Microblogs.js'; import edit from './pages/edit.js'; import userLine from './Userline.js'; +let authenticated; +const token = localStorage.FBIdToken; +if (token) { + const decodedToken = jwtDecode(token); + if (decodedToken.exp * 1000 < Date.now()) { + window.location.href = '/login'; + authenticated = false; + } else { + authenticated = true; + } +} + class App extends Component { render() { return ( @@ -24,9 +39,9 @@ class App extends Component {
- - - + + + diff --git a/twistter-frontend/src/pages/Login.js b/twistter-frontend/src/pages/Login.js index 76531d2..2686e84 100644 --- a/twistter-frontend/src/pages/Login.js +++ b/twistter-frontend/src/pages/Login.js @@ -1,26 +1,171 @@ -/* eslint-disable */ -import React, { Component } from 'react'; -import '../App.css'; - +import React, { Component } from "react"; +import axios from "axios"; +import PropTypes from "prop-types"; import logo from '../images/twistter-logo.png'; -import TextField from '@material-ui/core/TextField'; -class Login extends Component { - render() { - return ( -
- logo -

- Log in to Twistter -

- -

- -

- -
- ); +// Material-UI stuff +import Button from "@material-ui/core/Button"; +import CircularProgress from "@material-ui/core/CircularProgress"; +import Grid from "@material-ui/core/Grid"; +import TextField from "@material-ui/core/TextField"; +import Typography from "@material-ui/core/Typography"; +import withStyles from "@material-ui/core/styles/withStyles"; + +const styles = { + form: { + textAlign: "center" + }, + textField: { + marginBottom: 30 + }, + pageTitle: { + // marginTop: 20, + marginBottom: 40 + }, + button: { + positon: "relative", + marginBottom: 30 + }, + progress: { + position: "absolute" + } +}; + +export class Login extends Component { + // componentDidMount() { + // axios + // .get("/getProfileInfo") + // .then((res) => { + // this.setState({ + // firstName: res.data.firstName, + // lastName: res.data.lastName, + // email: res.data.email, + // handle: res.data.handle, + // bio: res.data.bio + // }); + // }) + // .catch((err) => { + // console.error(err); + // }); + // } + + // Constructor for the state + constructor() { + super(); + this.state = { + email: "", + password:"", + loading: false, + errors: {} + }; + } + + // Runs whenever the submit button is clicked. + // Updates the database entry of the signed in user with the + // data stored in the state. + handleSubmit = (event) => { + event.preventDefault(); + this.setState({ + loading: true + }); + const loginData = { + email: this.state.email, + password: this.state.password, + }; + axios + .post("/login", loginData) + .then((res) => { + // Save the login token + localStorage.setItem('FBIdToken', `Bearer ${res.data.token}`); + this.setState({ + loading: false + }); + // Redirects to home page + this.props.history.push('/home'); + }) + .catch((err) => { + this.setState({ + errors: err.response.data, + loading: false + }); + }); }; + + // Updates the state whenever one of the textboxes changes. + // The key is the name of the textbox and the value is the + // value in the text box. + handleChange = (event) => { + this.setState({ + [event.target.name]: event.target.value, + errors: { + [event.target.name]: null + } + }); + }; + + render() { + const { classes } = this.props; + const { errors, loading } = this.state; + + return ( + + + + logo + + Log in to Twistter + +
+ + + + {errors.general && ( + Wrong Email or Password + )} + +
+ + + ); + } } -export default Login; \ No newline at end of file +Login.propTypes = { + classes: PropTypes.object.isRequired +}; + +export default withStyles(styles)(Login); diff --git a/twistter-frontend/src/util/AuthRoute.js b/twistter-frontend/src/util/AuthRoute.js new file mode 100644 index 0000000..8cc2395 --- /dev/null +++ b/twistter-frontend/src/util/AuthRoute.js @@ -0,0 +1,11 @@ +import React from 'react' +import { Route, Redirect} from 'react-router-dom'; + +const AuthRoute = ({ component: Component, authenticated, ...rest}) => ( + authenticated === true ? : } + /> +) + +export default AuthRoute; From 5df28e0e77f843f7d42b0183d1f80f5e44a13e1a Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Wed, 2 Oct 2019 17:53:20 -0400 Subject: [PATCH 2/5] Still working on Auth State --- twistter-frontend/src/App.js | 80 +++++++---- twistter-frontend/src/index.js | 5 +- twistter-frontend/src/pages/Login.js | 52 +++---- .../src/redux/actions/dataActions.js | 0 .../src/redux/actions/userActions.js | 35 +++++ .../src/redux/reducers/dataReducer.js | 0 .../src/redux/reducers/uiReducer.js | 30 ++++ .../src/redux/reducers/userReducer.js | 28 ++++ twistter-frontend/src/redux/store.js | 27 ++++ twistter-frontend/src/redux/types.js | 12 ++ twistter-frontend/src/serviceWorker.js | 135 ++++++++++++++++++ twistter-frontend/src/util/AuthRoute.js | 19 ++- 12 files changed, 363 insertions(+), 60 deletions(-) create mode 100644 twistter-frontend/src/redux/actions/dataActions.js create mode 100644 twistter-frontend/src/redux/actions/userActions.js create mode 100644 twistter-frontend/src/redux/reducers/dataReducer.js create mode 100644 twistter-frontend/src/redux/reducers/uiReducer.js create mode 100644 twistter-frontend/src/redux/reducers/userReducer.js create mode 100644 twistter-frontend/src/redux/store.js create mode 100644 twistter-frontend/src/redux/types.js create mode 100644 twistter-frontend/src/serviceWorker.js diff --git a/twistter-frontend/src/App.js b/twistter-frontend/src/App.js index 4a13d53..df42968 100644 --- a/twistter-frontend/src/App.js +++ b/twistter-frontend/src/App.js @@ -1,30 +1,34 @@ /* eslint-disable */ -import React, { Component } from 'react'; +import React, { Component } from "react"; -import './App.css'; +import "./App.css"; -import { BrowserRouter as Router } from 'react-router-dom'; -import Route from 'react-router-dom/Route'; -import Navbar from './components/layout/NavBar'; -import jwtDecode from 'jwt-decode'; +import { BrowserRouter as Router } from "react-router-dom"; +import Route from "react-router-dom/Route"; +import Navbar from "./components/layout/NavBar"; +import jwtDecode from "jwt-decode"; + +// Redux +import { Provider } from "react-redux"; +import store from "./redux/store"; // Components -import AuthRoute from './util/AuthRoute'; +import AuthRoute from "./util/AuthRoute"; -import home from './pages/Home'; -import register from './pages/Register'; -import login from './pages/Login'; -import user from './pages/user'; -import writeMicroblog from './Writing_Microblogs.js'; -import edit from './pages/edit.js'; -import userLine from './Userline.js'; +import home from "./pages/Home"; +import register from "./pages/Register"; +import login from "./pages/Login"; +import user from "./pages/user"; +import writeMicroblog from "./Writing_Microblogs.js"; +import edit from "./pages/edit.js"; +import userLine from "./Userline.js"; let authenticated; const token = localStorage.FBIdToken; if (token) { const decodedToken = jwtDecode(token); if (decodedToken.exp * 1000 < Date.now()) { - window.location.href = '/login'; + window.location.href = "/login"; authenticated = false; } else { authenticated = true; @@ -34,21 +38,37 @@ if (token) { class App extends Component { render() { return ( - -
- -
-
- - - - - - - -
- -
+ + +
+ +
+
+ + + + + + + +
+
+
); } } diff --git a/twistter-frontend/src/index.js b/twistter-frontend/src/index.js index 5b9a1ed..f722945 100644 --- a/twistter-frontend/src/index.js +++ b/twistter-frontend/src/index.js @@ -1,8 +1,11 @@ import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; +import * as serviceWorker from './serviceWorker'; ReactDOM.render( , document.getElementById('root') -); \ No newline at end of file +); + +serviceWorker.unregister(); \ No newline at end of file diff --git a/twistter-frontend/src/pages/Login.js b/twistter-frontend/src/pages/Login.js index 2686e84..23f991f 100644 --- a/twistter-frontend/src/pages/Login.js +++ b/twistter-frontend/src/pages/Login.js @@ -11,6 +11,10 @@ import TextField from "@material-ui/core/TextField"; import Typography from "@material-ui/core/Typography"; import withStyles from "@material-ui/core/styles/withStyles"; +// Redux stuff +import { connect } from 'react-redux'; +import { loginUser } from '../redux/actions/userActions'; + const styles = { form: { textAlign: "center" @@ -55,40 +59,26 @@ export class Login extends Component { this.state = { email: "", password:"", - loading: false, errors: {} }; } + componentWillReceiveProps(nextProps) { + if (nextProps.UI.errors) { + this.setState({ errors: nextProps.UI.errors }); + } + } + // Runs whenever the submit button is clicked. // Updates the database entry of the signed in user with the // data stored in the state. handleSubmit = (event) => { event.preventDefault(); - this.setState({ - loading: true - }); const loginData = { email: this.state.email, password: this.state.password, }; - axios - .post("/login", loginData) - .then((res) => { - // Save the login token - localStorage.setItem('FBIdToken', `Bearer ${res.data.token}`); - this.setState({ - loading: false - }); - // Redirects to home page - this.props.history.push('/home'); - }) - .catch((err) => { - this.setState({ - errors: err.response.data, - loading: false - }); - }); + this.props.loginUser(loginData, this.props.history); }; // Updates the state whenever one of the textboxes changes. @@ -104,8 +94,8 @@ export class Login extends Component { }; render() { - const { classes } = this.props; - const { errors, loading } = this.state; + const { classes, UI: { loading } } = this.props; + const { errors } = this.state; return ( @@ -165,7 +155,19 @@ export class Login extends Component { } Login.propTypes = { - classes: PropTypes.object.isRequired + classes: PropTypes.object.isRequired, + loginUser: PropTypes.func.isRequired, + user: PropTypes.object.isRequired, + UI: PropTypes.object.isRequired }; -export default withStyles(styles)(Login); +const mapStateToProps = (state) => ({ + user: state.user, + UI: state.UI, +}); + +const mapActionsToProps = { + loginUser +} + +export default connect(mapStateToProps, mapActionsToProps)(withStyles(styles)(Login)); diff --git a/twistter-frontend/src/redux/actions/dataActions.js b/twistter-frontend/src/redux/actions/dataActions.js new file mode 100644 index 0000000..e69de29 diff --git a/twistter-frontend/src/redux/actions/userActions.js b/twistter-frontend/src/redux/actions/userActions.js new file mode 100644 index 0000000..e7e5535 --- /dev/null +++ b/twistter-frontend/src/redux/actions/userActions.js @@ -0,0 +1,35 @@ +import {SET_USER, SET_ERRORS, CLEAR_ERRORS, LOADING_UI} from '../types'; +import axios from 'axios'; + +export const loginUser = (loginData, history) => (dispatch) => { + dispatch({ type: LOADING_UI }); + axios + .post("/login", loginData) + .then((res) => { + // Save the login token + const FBIdToken = `Bearer ${res.data.token}`; + localStorage.setItem('FBIdToken', FBIdToken); + axios.defaults.headers.common['Authorization'] = FBIdToken; + dispatch(getProfileInfo()); + dispatch({ type: CLEAR_ERRORS }) + // Redirects to home page + history.push('/home'); + }) + .catch((err) => { + dispatch ({ + type: SET_ERRORS, + payload: err.response.data, + }) + }); +} + +export const getProfileInfo = () => (dispatch) => { + axios.get('/getProfileInfo') + .then((res) => { + dispatch({ + type: SET_USER, + payload: res.data, + }) + }) + .catch((err) => console.error(err)); +} \ No newline at end of file diff --git a/twistter-frontend/src/redux/reducers/dataReducer.js b/twistter-frontend/src/redux/reducers/dataReducer.js new file mode 100644 index 0000000..e69de29 diff --git a/twistter-frontend/src/redux/reducers/uiReducer.js b/twistter-frontend/src/redux/reducers/uiReducer.js new file mode 100644 index 0000000..65e781d --- /dev/null +++ b/twistter-frontend/src/redux/reducers/uiReducer.js @@ -0,0 +1,30 @@ +import { SET_ERRORS, CLEAR_ERRORS, LOADING_UI } from '../types'; + +const initialState = { + loading: false, + errors: null +}; + +export default function(state = initialState, action) { + switch(action.type) { + case SET_ERRORS: + return { + ...state, + loading: false, + errors: action.payload + }; + case CLEAR_ERRORS: + return { + ...state, + loading: false, + errors: null + }; + case LOADING_UI: + return { + ...state, + loading: true + } + default: + return state; + } +} \ No newline at end of file diff --git a/twistter-frontend/src/redux/reducers/userReducer.js b/twistter-frontend/src/redux/reducers/userReducer.js new file mode 100644 index 0000000..7a29e90 --- /dev/null +++ b/twistter-frontend/src/redux/reducers/userReducer.js @@ -0,0 +1,28 @@ +import {SET_USER, SET_ERRORS, CLEAR_ERRORS, LOADING_UI, SET_AUTHENTICATED, SET_UNAUTHENTICATED} from '../types'; + +const initialState = { + authenticated: false, + credentials: {}, + likes: [], + notifications: [] +}; + +export default function(state = initialState, action) { + switch(action.type) { + case SET_AUTHENTICATED: + return { + ...state, + authenticated: true, + + }; + case SET_UNAUTHENTICATED: + return initialState; + case SET_USER: + return { + authenticated: true, + ...action.payload, + }; + default: + return state; + } +} \ No newline at end of file diff --git a/twistter-frontend/src/redux/store.js b/twistter-frontend/src/redux/store.js new file mode 100644 index 0000000..b79ebe6 --- /dev/null +++ b/twistter-frontend/src/redux/store.js @@ -0,0 +1,27 @@ +import { createStore, combineReducers, applyMiddleware, compose } from "redux"; +import thunk from "redux-thunk"; + +import userReducer from "./reducers/userReducer"; +import dataReducer from "./reducers/dataReducer"; +import uiReducer from "./reducers/uiReducer"; + +const initialState = {}; + +const middleWare = [thunk]; + +const reducers = combineReducers({ + user: userReducer, + data: dataReducer, + UI: uiReducer +}); + +const store = createStore( + reducers, + initialState, + compose( + applyMiddleware(...middleWare), + window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() + ) +); + +export default store; diff --git a/twistter-frontend/src/redux/types.js b/twistter-frontend/src/redux/types.js new file mode 100644 index 0000000..6f16afc --- /dev/null +++ b/twistter-frontend/src/redux/types.js @@ -0,0 +1,12 @@ +// User reducer types +export const SET_AUTHENTICATED = 'SET_AUTHENTICATED'; +export const SET_UNAUTHENTICATED = 'SET_UNAUTHENTICATED'; +export const SET_USER = 'SET_USER'; +export const LOADING_USER = 'LOADING_USER'; + +// UI reducer types +export const SET_ERRORS = 'SET_ERRORS'; +export const LOADING_UI = 'LOADING_UI'; +export const CLEAR_ERRORS = 'CLEAR_ERRORS'; + +// Data reducer types \ No newline at end of file diff --git a/twistter-frontend/src/serviceWorker.js b/twistter-frontend/src/serviceWorker.js new file mode 100644 index 0000000..b685ab1 --- /dev/null +++ b/twistter-frontend/src/serviceWorker.js @@ -0,0 +1,135 @@ +// This optional code is used to register a service worker. +// register() is not called by default. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. + +// To learn more about the benefits of this model and instructions on how to +// opt-in, read https://bit.ly/CRA-PWA + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.1/8 is considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) + ); + + export function register(config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://bit.ly/CRA-PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } + } + + function registerValidSW(swUrl, config) { + navigator.serviceWorker + .register(swUrl) + .then(registration => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log( + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' + ); + + // Execute callback + if (config && config.onUpdate) { + config.onUpdate(registration); + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.'); + + // Execute callback + if (config && config.onSuccess) { + config.onSuccess(registration); + } + } + } + }; + }; + }) + .catch(error => { + console.error('Error during service worker registration:', error); + }); + } + + function checkValidServiceWorker(swUrl, config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl) + .then(response => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if ( + response.status === 404 || + (contentType != null && contentType.indexOf('javascript') === -1) + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then(registration => { + registration.unregister().then(() => { + window.location.reload(); + }); + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log( + 'No internet connection found. App is running in offline mode.' + ); + }); + } + + export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready.then(registration => { + registration.unregister(); + }); + } + } diff --git a/twistter-frontend/src/util/AuthRoute.js b/twistter-frontend/src/util/AuthRoute.js index 8cc2395..309ccf0 100644 --- a/twistter-frontend/src/util/AuthRoute.js +++ b/twistter-frontend/src/util/AuthRoute.js @@ -1,11 +1,22 @@ import React from 'react' import { Route, Redirect} from 'react-router-dom'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; -const AuthRoute = ({ component: Component, authenticated, ...rest}) => ( +const AuthRoute = ({ component: Component, authenticated, ...rest }) => ( authenticated === true ? : } + render={(props) => + authenticated === true ? : } /> -) +); -export default AuthRoute; +const mapStateToProps = (state) => ({ + authenticated: state.user.authenticated +}); + +AuthRoute.propTypes = { + user: PropTypes.object +} + +export default connect(mapStateToProps)(AuthRoute); From 8de496826a700ef5aa2e3c81917b3d5e289b2f03 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Wed, 2 Oct 2019 22:53:31 -0400 Subject: [PATCH 3/5] Testing login backend --- functions/util/fbAuth.js | 7 +++++++ twistter-frontend/package.json | 2 +- twistter-frontend/src/pages/edit.js | 2 ++ .../src/redux/actions/userActions.js | 20 +++++++++---------- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/functions/util/fbAuth.js b/functions/util/fbAuth.js index a9243cc..3b59d14 100644 --- a/functions/util/fbAuth.js +++ b/functions/util/fbAuth.js @@ -4,6 +4,13 @@ const { admin, db } = require('./admin'); // The function will only execute if the user is logged in, or rather, they have // a valid token module.exports = (req, res, next) => { + console.log(req); + console.log(req.body); + console.log(req.headers); + console.log(req.headers.authorization); + console.log(JSON.stringify(req.body)); + console.log(JSON.stringify(req.header)); + let idToken; // Checking that the token exists in the header of the request diff --git a/twistter-frontend/package.json b/twistter-frontend/package.json index a83c175..eebb8fb 100644 --- a/twistter-frontend/package.json +++ b/twistter-frontend/package.json @@ -37,5 +37,5 @@ "last 1 safari version" ] }, - "proxy": "https://us-central1-twistter-e4649.cloudfunctions.net/api" + "proxy": " http://localhost:5001/twistter-e4649/us-central1/api" } diff --git a/twistter-frontend/src/pages/edit.js b/twistter-frontend/src/pages/edit.js index 306e19b..14d5172 100644 --- a/twistter-frontend/src/pages/edit.js +++ b/twistter-frontend/src/pages/edit.js @@ -85,6 +85,7 @@ export class edit extends Component { axios .post("/updateProfileInfo", newProfileData) .then((res) => { + console.log(res); this.setState({ loading: false }); @@ -92,6 +93,7 @@ export class edit extends Component { // TODO: Need to redirect user to their profile page }) .catch((err) => { + console.log(err); this.setState({ errors: err.response.data, loading: false diff --git a/twistter-frontend/src/redux/actions/userActions.js b/twistter-frontend/src/redux/actions/userActions.js index e7e5535..2d87738 100644 --- a/twistter-frontend/src/redux/actions/userActions.js +++ b/twistter-frontend/src/redux/actions/userActions.js @@ -23,13 +23,13 @@ export const loginUser = (loginData, history) => (dispatch) => { }); } -export const getProfileInfo = () => (dispatch) => { - axios.get('/getProfileInfo') - .then((res) => { - dispatch({ - type: SET_USER, - payload: res.data, - }) - }) - .catch((err) => console.error(err)); -} \ No newline at end of file +// export const getProfileInfo = () => (dispatch) => { +// axios.get('/getProfileInfo') +// .then((res) => { +// dispatch({ +// type: SET_USER, +// payload: res.data, +// }) +// }) +// .catch((err) => console.error(err)); +// } \ No newline at end of file From f14e8bd97083442b32c15db7062479ea8b3f3845 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Thu, 3 Oct 2019 10:58:45 -0400 Subject: [PATCH 4/5] Redux saves user data on login --- functions/handlers/users.js | 17 ++++++++++++++ functions/index.js | 3 +++ twistter-frontend/package.json | 2 +- .../src/redux/actions/userActions.js | 22 +++++++++---------- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/functions/handlers/users.js b/functions/handlers/users.js index 1c217e5..21f9b96 100644 --- a/functions/handlers/users.js +++ b/functions/handlers/users.js @@ -214,3 +214,20 @@ exports.getUserDetails = (req, res) => { return res.status(500).json({ error: err.code }); }); }; + +exports.getAuthenticatedUser = (req, res) => { + let userData = {}; + db.doc(`/users/${req.user.handle}`) + .get() + .then((doc) => { + if (doc.exists) { + userData.credentials = doc.data(); + return res.status(200).json({userData}); + } else { + return res.status(400).json({error: "User not found."}) + }}) + .catch((err) => { + console.error(err); + return res.status(500).json({ error: err.code }); + }); +}; diff --git a/functions/index.js b/functions/index.js index eb99cbf..5c728bc 100644 --- a/functions/index.js +++ b/functions/index.js @@ -10,6 +10,7 @@ app.use(cors()); * handlers/users.js * *------------------------------------------------------------------*/ const { + getAuthenticatedUser, getUserDetails, getProfileInfo, login, @@ -34,6 +35,8 @@ app.get("/getProfileInfo", fbAuth, getProfileInfo); // Updates the currently logged in user's profile information app.post("/updateProfileInfo", fbAuth, updateProfileInfo); +app.get("/user", fbAuth, getAuthenticatedUser); + /*------------------------------------------------------------------* * handlers/post.js * *------------------------------------------------------------------*/ diff --git a/twistter-frontend/package.json b/twistter-frontend/package.json index eebb8fb..a83c175 100644 --- a/twistter-frontend/package.json +++ b/twistter-frontend/package.json @@ -37,5 +37,5 @@ "last 1 safari version" ] }, - "proxy": " http://localhost:5001/twistter-e4649/us-central1/api" + "proxy": "https://us-central1-twistter-e4649.cloudfunctions.net/api" } diff --git a/twistter-frontend/src/redux/actions/userActions.js b/twistter-frontend/src/redux/actions/userActions.js index 2d87738..2177a75 100644 --- a/twistter-frontend/src/redux/actions/userActions.js +++ b/twistter-frontend/src/redux/actions/userActions.js @@ -10,7 +10,7 @@ export const loginUser = (loginData, history) => (dispatch) => { const FBIdToken = `Bearer ${res.data.token}`; localStorage.setItem('FBIdToken', FBIdToken); axios.defaults.headers.common['Authorization'] = FBIdToken; - dispatch(getProfileInfo()); + dispatch(getUserData()); dispatch({ type: CLEAR_ERRORS }) // Redirects to home page history.push('/home'); @@ -23,13 +23,13 @@ export const loginUser = (loginData, history) => (dispatch) => { }); } -// export const getProfileInfo = () => (dispatch) => { -// axios.get('/getProfileInfo') -// .then((res) => { -// dispatch({ -// type: SET_USER, -// payload: res.data, -// }) -// }) -// .catch((err) => console.error(err)); -// } \ No newline at end of file +export const getUserData = () => (dispatch) => { + axios.get('/user') + .then((res) => { + dispatch({ + type: SET_USER, + payload: res.data, + }) + }) + .catch((err) => console.error(err)); +} \ No newline at end of file From 7841fa179807daad871e9c3d73019f3ccdeee40f Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Thu, 3 Oct 2019 11:23:28 -0400 Subject: [PATCH 5/5] Fix warning --- .../src/redux/actions/userActions.js | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/twistter-frontend/src/redux/actions/userActions.js b/twistter-frontend/src/redux/actions/userActions.js index 2177a75..cc6eb56 100644 --- a/twistter-frontend/src/redux/actions/userActions.js +++ b/twistter-frontend/src/redux/actions/userActions.js @@ -1,6 +1,18 @@ import {SET_USER, SET_ERRORS, CLEAR_ERRORS, LOADING_UI} from '../types'; import axios from 'axios'; + +export const getUserData = () => (dispatch) => { + axios.get('/user') + .then((res) => { + dispatch({ + type: SET_USER, + payload: res.data, + }) + }) + .catch((err) => console.error(err)); +} + export const loginUser = (loginData, history) => (dispatch) => { dispatch({ type: LOADING_UI }); axios @@ -21,15 +33,4 @@ export const loginUser = (loginData, history) => (dispatch) => { payload: err.response.data, }) }); -} - -export const getUserData = () => (dispatch) => { - axios.get('/user') - .then((res) => { - dispatch({ - type: SET_USER, - payload: res.data, - }) - }) - .catch((err) => console.error(err)); } \ No newline at end of file