diff --git a/client/src/actions/index.js b/client/src/actions/index.js index 062ac16..c1fb99f 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -1,39 +1,47 @@ -import axios from 'axios'; -import { FETCH_USER, - FETCH_EXPLORE_QUOTES, - SAVE_QUOTE_TO_PROFILE, - REMOVE_QUOTE_FROM_PROFILE } from '../constants/constants'; +import axios from "axios"; +import { + FETCH_USER, + FETCH_EXPLORE_QUOTES, + SAVE_QUOTE_TO_PROFILE, + REMOVE_QUOTE_FROM_PROFILE, +} from "../constants/constants"; export const fetchUser = (user) => { - return dispatch => { - axios.get('/api/user', {withCredentials: 'include'}) - .then(res => res.data) - .then(user => dispatch({ type: FETCH_USER, payload: user})) - .catch(err => console.log(err)) - } -} + return (dispatch) => { + axios + .get("/api/user", { withCredentials: "include" }) + .then((res) => res.data) + .then((user) => dispatch({ type: FETCH_USER, payload: user })) + .catch((err) => console.log(err)); + }; +}; export const fetchExploreQuotes = () => { - return dispatch => { - axios.get('/api/quotes') - .then(res => res.data) - .then(data => dispatch({type: FETCH_EXPLORE_QUOTES, payload: data})) - .catch(err => console.log(err)) - } -} + return (dispatch) => { + axios + .get("/api/quotes") + .then((res) => res.data) + .then((data) => dispatch({ type: FETCH_EXPLORE_QUOTES, payload: data })) + .catch((err) => console.log(err)); + }; +}; export const saveQuoteToProfile = (quote) => { - return dispatch => { - axios.post('/api/saved', quote) - .then(data => dispatch({ type: SAVE_QUOTE_TO_PROFILE, payload: data })) - .catch(err => console.log(err)) - } -} + return (dispatch) => { + axios + .post("/api/quotes/save", quote) + .then((data) => dispatch({ type: SAVE_QUOTE_TO_PROFILE, payload: data })) + .catch((err) => console.log(err)); + }; +}; export const removeQuoteFromProfile = (id) => { - return dispatch => { - axios.delete(`/api/saved/${id}`) - .then(data => dispatch({ type: REMOVE_QUOTE_FROM_PROFILE, payload: data })) - .catch(err => console.log(err)) - } -} \ No newline at end of file + return (dispatch) => { + axios + .delete(`/api/saved/${id}`) + .then((data) => + dispatch({ type: REMOVE_QUOTE_FROM_PROFILE, payload: data }) + ) + .catch((err) => console.log(err)); + }; +}; diff --git a/client/src/components/App.js b/client/src/components/App.js index de015f4..32298e9 100644 --- a/client/src/components/App.js +++ b/client/src/components/App.js @@ -1,6 +1,5 @@ import React, { Component } from "react"; import { BrowserRouter as Router, Route } from "react-router-dom"; - import LandingPage from "../pages/LandingPage"; import Header from "./Header"; import Dashboard from "../pages/Dashboard"; @@ -8,6 +7,7 @@ import ExplorePage from "../pages/ExplorePage"; import MindfulnessPage from "../pages/MindfulnessPage"; import JournalingPage from "../pages/JournalingPage"; import SignUpPage from "../pages/SignUpPage"; +import LoginPage from "../pages/LoginPage"; class App extends Component { render() { @@ -18,6 +18,7 @@ class App extends Component {
+ diff --git a/client/src/components/Header.js b/client/src/components/Header.js index aca2303..7348312 100644 --- a/client/src/components/Header.js +++ b/client/src/components/Header.js @@ -33,10 +33,10 @@ const Header = ({ user }) => { ) : ( <>
  • - Login + Login
  • - Sign Up + Sign Up
  • )} diff --git a/client/src/pages/Dashboard.js b/client/src/pages/Dashboard.js index 1c8fdd5..98e028a 100644 --- a/client/src/pages/Dashboard.js +++ b/client/src/pages/Dashboard.js @@ -11,8 +11,7 @@ class Dashboard extends Component { this.props.fetchUser(); } - renderSavedQuotes = () => { - const { user } = this.props; + renderSavedQuotes = (user) => { return user.savedQuotes.reverse().map((quote, i) => { return ; }); @@ -20,17 +19,19 @@ class Dashboard extends Component { render() { const { user } = this.props; + console.log(user); return (
    - {user.savedQuotes === undefined ? ( +

    Hello {user.username}

    + {user.savedQuotes && user.savedQuotes.length ? ( + this.renderSavedQuotes(user) + ) : (

    {" "} You don't have any quotes yet. Click here to start!

    - ) : ( - this.renderSavedQuotes() )}
    diff --git a/client/src/pages/LoginPage.js b/client/src/pages/LoginPage.js new file mode 100644 index 0000000..4102b5b --- /dev/null +++ b/client/src/pages/LoginPage.js @@ -0,0 +1,64 @@ +import React, { Component } from "react"; +import { Redirect } from "react-router-dom"; +import axios from "axios"; + +class LoginPage extends Component { + constructor() { + super(); + + this.state = { + username: "", + password: "", + errors: {}, + }; + } + + handleChange = (e) => { + this.setState({ + [e.target.name]: e.target.value, + }); + }; + + handleSubmit = (e) => { + const { username, password } = this.state; + e.preventDefault(); + + axios + .post("/auth/local", { username, password }) + .then(() => ) + .catch((error) => { + if (error.response) { + console.log(this.state); + this.setState({ ...this.state, errors: error.response.data }); + } + }); + }; + + render() { + const { username, password, errors } = this.state; + return ( +
    +
    + + + {errors.length ?

    {errors}

    : null} + +
    +
    + ); + } +} + +export default LoginPage; diff --git a/client/src/pages/SignUpPage.js b/client/src/pages/SignUpPage.js index 5be3e1b..91d7f67 100644 --- a/client/src/pages/SignUpPage.js +++ b/client/src/pages/SignUpPage.js @@ -14,12 +14,9 @@ class SignUpPage extends Component { } handleChange = (e) => { - this.setState( - { - [e.target.name]: e.target.value, - }, - () => console.log(this.state) - ); + this.setState({ + [e.target.name]: e.target.value, + }); }; checkPassword = () => { @@ -27,7 +24,8 @@ class SignUpPage extends Component { }; handleSubmit = (e) => { - const { username, password } = this.state; + let { username, password } = this.state; + username = username.toLowerCase(); e.preventDefault(); this.checkPassword(); @@ -78,7 +76,7 @@ class SignUpPage extends Component { {errors ? (

    Passwords don't match

    ) : null} - +
    ); diff --git a/client/src/reducers/authReducer.js b/client/src/reducers/authReducer.js index 42e4a6d..73d732f 100644 --- a/client/src/reducers/authReducer.js +++ b/client/src/reducers/authReducer.js @@ -3,7 +3,6 @@ import { FETCH_USER } from "../constants/constants"; export const authReducer = (state = {}, action) => { switch (action.type) { case FETCH_USER: - console.log(action.payload); return action.payload || null; default: return state; diff --git a/index.js b/index.js index 9220e9a..ddc518f 100644 --- a/index.js +++ b/index.js @@ -32,6 +32,8 @@ app.use( }) ); +app.use(express.static(`${__dirname}/client/public`)); + // Passport middleware app.use(passport.initialize()); diff --git a/models/User.js b/models/User.js index 9cecce4..5a8f04c 100644 --- a/models/User.js +++ b/models/User.js @@ -4,7 +4,7 @@ const mongoose = require("mongoose"), const userSchema = new Schema( { - username: String, + username: { type: String, unique: true }, password: String, avatar: String, savedQuotes: [quoteSchema], diff --git a/routes/genRoutes.js b/routes/genRoutes.js index 6b26f0b..cf88e82 100644 --- a/routes/genRoutes.js +++ b/routes/genRoutes.js @@ -2,15 +2,15 @@ const express = require("express"), passport = require("passport"), app = express(); -module.exports = app => { - app.use(function(req, res, next) { - res.header("Access-Control-Allow-Origin", "*"); - res.header( - "Access-Control-Allow-Headers", - "Origin, X-Requested-With, Content-Type, Accept" - ); - next(); - }); +module.exports = (app) => { + // app.use(function(req, res, next) { + // res.header("Access-Control-Allow-Origin", "*"); + // res.header( + // "Access-Control-Allow-Headers", + // "Origin, X-Requested-With, Content-Type, Accept" + // ); + // next(); + // }); app.get("/api/user", (req, res) => { res.send(req.user); diff --git a/routes/localRoutes.js b/routes/localRoutes.js index 0135665..db2891a 100644 --- a/routes/localRoutes.js +++ b/routes/localRoutes.js @@ -5,10 +5,19 @@ const express = require("express"), module.exports = (app) => { app.post( "/auth/local", - passport.authenticate("local", { failureRedirect: "/signup" }), + passport.authenticate( + "local" + // { + // successRedirect: "/dashboard", + // failureRedirect: "/signup", + // } + ), (req, res) => { - console.log(res); - res.redirect("/dashboard"); + if (req.user) { + res.redirect("/dashboard"); + } else { + res.redirect("/login"); + } } ); }; diff --git a/routes/quotesRoutes.js b/routes/quotesRoutes.js index 8267f40..d7e4d25 100644 --- a/routes/quotesRoutes.js +++ b/routes/quotesRoutes.js @@ -1,39 +1,39 @@ -const express = require('express'), - User = require('../models/User'), - fetch = require('node-fetch') - app = express(); +const express = require("express"), + User = require("../models/User"), + fetch = require("node-fetch"); +app = express(); module.exports = (app) => { + app.get("/api/quotes", async (req, res) => { + const result = await fetch( + "https://api.forismatic.com/api/1.0/?method=getQuote&lang=en&format=json&lang=en" + ); + const json = await result.json(); - app.get('/api/quotes', async (req, res) => { - const result = await fetch('https://api.forismatic.com/api/1.0/?method=getQuote&lang=en&format=json&lang=en') - const json = await result.json(); - - res.send(json) - }) - - // Add Quote - app.post('/api/saved', (req, res) => { - const {author, quote} = req.body; - - const newQuote = User.findOne({ id: req.user.id }, (err, user) => { - user.savedQuotes.push({ - author, - quote, - isSaved: true - }); - user.save(); - }); - - }) + res.send(json); + }); - // Remove Quote - app.delete('/api/saved/:id', (req, res, next) => { + // Add Quote + app.post("/api/quotes/save", (req, res) => { + const { author, quote } = req.body; + const { _id } = req.user; - const user = User.findOne({ _id: req.user._id}, (err, user) => { - user.savedQuotes.id(req.params.id).remove(); + const newQuote = User.findOne({ _id }, (err, user) => { + user.savedQuotes.push({ + author, + quote, + isSaved: true, + }); + user.save(); + }); + }); - user.save(); - }); - }) -} \ No newline at end of file + // Remove Quote + app.delete("/api/saved/:id", (req, res, next) => { + const user = User.findOne({ _id: req.user._id }, (err, user) => { + user.savedQuotes.id(req.params.id).remove(); + + user.save(); + }); + }); +}; diff --git a/services/passport.js b/services/passport.js index 765ec7d..afbb429 100644 --- a/services/passport.js +++ b/services/passport.js @@ -14,8 +14,7 @@ passport.serializeUser((user, done) => { }); passport.deserializeUser((id, done) => { - const userId = mongoose.Types.ObjectId(id); - User.findById(userId, (err, user) => { + User.findById(id, (err, user) => { done(err, user); }); }); @@ -36,7 +35,6 @@ passport.use( if (existingUser) { return done(null, existingUser); } - // Create new User const newUser = await new User({ username: profile.displayName, @@ -103,25 +101,47 @@ passport.use( ) ); +// Local Strategy + passport.use( + "local", new LocalStrategy(async (username, password, done) => { - console.log(username, password); - try { - const existingUser = await User.findOne({ username: username }); + const existingUser = await User.findOne({ username }); + // If login user doesn't exist, throw error - existingUser ? done(null, existingUser) : done(null, false); + if (!existingUser) { + return done(null, false, { message: "User not found." }); + } - const newUser = await new User({ - username, - password, - avatar: null, - savedQuotes: [], - }).save(); + // If username exists, check password - done(null, newUser); + const validPassword = () => + username && password === existingUser.password; + + if (!validPassword) { + return done(null, false, { message: "Invalid password" }); + } + + // If username is found and password is valid, return the user + + if (existingUser && validPassword) { + console.log("existingUser", existingUser); + done(null, existingUser); + } + // Otherwise, create a new user + else { + const newUser = await new User({ + username, + password, + avatar: null, + savedQuotes: [], + }).save(); + + done(null, newUser); + } } catch (error) { - done(error); + done(error, false, { message: error }); } }) );