How to fetch data in React/Redux from mongoose/mongodb using router to reflect changes in state of component?

孤人 提交于 2020-06-17 09:08:10

问题


Trying to render a component only the first time user logs into my MERN app to show a questionnaire, otherwise user is taken to the dashboard. I am able to manipulate redux state to show firstLogin as changing in my auth reducer by using an action that sets firstlogin to true (independent of the FirstLogin value changed in my database) after the user fills the questionnaire and even update the value of FirstLogin in the User's collection in my mongodb.

I am sharing my authActions authReducer, users.js and components Dashboard and Assessment.

~AuthActions~
import axios from "axios";
import setAuthToken from "../utils/setAuthToken";
import jwt_decode from "jwt-decode";

import { GET_ERRORS, SET_CURRENT_USER, USER_LOADING, UPDATE_USER } from "./types";

// Register User
export const registerUser = (userData, history) => dispatch => {
  axios
    .post("/api/users/register", userData)
    .then(res => history.push("/login"))
    // .then(res => {
    //   if(userData.FirstLogin){
    //     history.push("/login")
    //   }
    // })
    .catch(err => 
      dispatch({
        type: GET_ERRORS,
        payload: err.response.data
      })
    );
};

//Save assessment data and set firstLogin to true
export const createAssessment = (newAssessment, history) => dispatch => {
  axios
    .post("/api/users/assessment", newAssessment)
    .then(assessment => {
      // in routes for assessment configure postedBy property(of user) to return true after assignment is submitted
      const value = true
      dispatch(updateUser(value))
      history.push("/dashboard");
      }).catch(err => 
     dispatch({
        type: GET_ERRORS,
        payload: err.response.data
      }))
    // axios.get("api/users/dashboard", newAssessment.email).then()
    };

// Login - get user token
export const loginUser = userData => dispatch => {
  axios
    .post("/api/users/login", userData)
    .then(res => {
      // Save to localStorage

      // Set token to localStorage
      const { token } = res.data;
      localStorage.setItem("jwtToken", token);
      // Set token to Auth header
      setAuthToken(token);
      // Decode token to get user data
      const decoded = jwt_decode(token);
      // Set current user
      dispatch(setCurrentUser(decoded));
    })
    .catch(err =>
      dispatch({
        type: GET_ERRORS,
        payload: err.response.data
      })
    );
};


export const updateUser = (value) => {
    return{
      type: UPDATE_USER,
      payload: value
    };
  };


// Set logged in user
export const setCurrentUser = decoded => {
  return {
    type: SET_CURRENT_USER,
    payload: decoded
  };
};

// User loading
export const setUserLoading = () => {
  return {
    type: USER_LOADING
  };
};

// Log user out
export const logoutUser = () => dispatch => {
  // Remove token from local storage
  localStorage.removeItem("jwtToken");
  // Remove auth header for future requests
  setAuthToken(false);
  // Set current user to empty object {} which will set isAuthenticated to false
  dispatch(setCurrentUser({}));
};

~authReducer~
import { SET_CURRENT_USER, UPDATE_USER, USER_LOADING } from "../actions/types";

const isEmpty = require("is-empty");

const initialState = {
  isAuthenticated: false,
  user: {},
  loading: false,
  firstLogin: false
};

export default function(state = initialState, action) {
  switch (action.type) {
    case SET_CURRENT_USER:
      return {
        ...state,
        isAuthenticated: !isEmpty(action.payload),
        user: action.payload,
        firstLogin: false
      };
    case USER_LOADING:
      return {
        ...state,
        loading: true
      };
    case UPDATE_USER:
      return {
        ...state,
        firstLogin: action.payload
      };
    default:
      return state;
  }
}
const express = require("express");
const router = express.Router();
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const multer = require('multer');
const mongoose = require("mongoose");
// const { v4: uuidV4 } = require('uuid');
const keys = require("../../config/keys");
const passport = require("passport");
var crypto = require('crypto');
// var nodemailer = require('nodemailer');
// var sgTransport = require('nodemailer-sendgrid-transport');
// const sendEmail = require('./email.send');
// const msgs = require('./email.msgs');
// const templates = require('./email.templates');
// Load input validation
const validateRegisterInput = require("../../validation/register");
const validateLoginInput = require("../../validation/login");
const { check, validationResult } = require('express-validator');

// Load User model and Token model
const User = require("../../models/User");
// const Token = require("../../models/Token")
const registeredemails = require("../../models/RegisteredEmails");  
const Assessment = require("../../models/Assessment");



// @route POST api/users/register
// @desc Register user
// @access Public
router.post("/register", type, function (req, res, next) {
    // var tmp_path = req.file.path;
    if(!req.file){
      console.log("File missing");
    }

  // Form validation
    const { errors, isValid } = validateRegisterInput(req.body);
    const url = req.protocol + '://' + req.get('host')


    // Check validation
    if (!isValid) {
      return res.status(400).json(errors);
    }

    //Checks email against registered emails in database table
    registeredemails.findOne({ email: req.body.email}).select("email").lean().then(result => {
      if (!result) {
          return res.status(400).json({email: "Email not provided"});
      }
    });

    User.findOne({ email: req.body.email }).then(user => 
      {
        if (user) {return res.status(400).json({ email: "Email already exists" })
      } 
      else {
        const newUser = new User({
                firstName: req.body.firstName,
                lastName: req.body.lastName,
                email: req.body.email,
                password: req.body.password,
                fileimg: url + '/public/' + req.file.filename
            });
            // // Hash password before saving in database
            bcrypt.genSalt(10, (err, salt) => {
              bcrypt.hash(newUser.password, salt, (err, hash) => {
                if (err) throw err;
                newUser.password = hash;
                newUser
                .save().then(user => {res.json(user)})
                .catch(err => console.log(err))
       });
      })
    }
  })
});


router.get("/dashboard", (req, res, next) => {
  User.find({}).then(user => {
    res.json(user);
  })
})

router.post("/assessment", (req, res, next) => {
  if(!req.body){
    console.log("No assessment data recieved");
  }else{
        User.findOne({email: req.body.email}).then(user => {
          user.firstLogin = true;
          user.save();

              Assessment.findOne({uAge: req.body.uAge}).then(assessment => 
                {
                  if (assessment) {return res.status(400).json({ assessment: "Assessment already exists" })
                } 
                else { 
                      var assessment = new Assessment({
                        uAge: req.body.uAge,
                        uCountry : req.body.uCountry
                      });

                      assessment.save(function (err, data) {
                        if (err) {
                          console.log(err);
                          res.send(err.message);
                          return;
                        }else{
                          res.send('success');
                          return;
                        }
                      });

                    }
                });
            })}
          });


// @route POST api/users/login
// @desc Login user and return JWT token
// @access Public
router.post("/login", (req, res) => {
  // Form validation

  const { errors, isValid } = validateLoginInput(req.body);

  // Check validation
  if (!isValid) {
    return res.status(400).json(errors);
  }

  const email = req.body.email;
  const password = req.body.password;

  // Find user by email
  User.findOne({ email }).then(user => {
    // Check if user exists
    if (!user) {
      return res.status(404).json({ emailnotfound: "Email not found" });
    }



    // Make sure the user has been verified
    // if (!user.confirmed) return res.status(401).send({ type: 'not-verified', msg: 'Your account has not been verified.' });

    // Check password
    bcrypt.compare(password, user.password).then(isMatch => {
      if (isMatch) {
        // User matched
        // Create JWT Payload
        const payload = {
          id: user.id,
          name: user.firstName
        };

        // Sign token
        jwt.sign(
          payload,
          keys.secretOrKey,
          {
            expiresIn: 31556926 // 1 year in seconds
          },
          (err, token) => {
            res.json({
              success: true,
              token: "Bearer " + token
            });
          }
        );
      } else {
        return res
          .status(400)
          .json({ passwordincorrect: "Password incorrect" });
      }
    });
  });
});

module.exports = router;
~Assessment~
import React, { Component } from "react";
import axios from "axios";
import { Link, withRouter } from "react-router-dom";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { createAssessment } from "../../actions/authActions";
import classnames from "classnames";
import { Container, Row, Col } from 'reactstrap';
// import { Button, Form, FormGroup, Label, Input, FormText } from 'reactstrap';
import UserNavbar from "../dashboard/UserNavbar.js";
// import { notify } from 'react-notify-toast'
// import { API_URL } from './../../config'
import { Button } from '@material-ui/core';
// import './register.css';

class AssessmentSimple extends Component {
  constructor() {
    super();
    this.state = {
      uAge:  "",
      email: "",
    //   uGender: '',
      uCountry: ""
    };
  }

    componentDidMount() {
    // If logged in and user navigates to Login page, should redirect them to dashboard
    if (this.props.auth.firstLogin) {
      this.props.history.push("/dashboard");
    }
  }


  onChange = e => {
    this.setState({ [e.target.id]: e.target.value });
  };


  onSubmit = e => {
     e.preventDefault();

    // const { email, username, password } = this.state
    // const { user } = this.props.auth;

    const  newAssessment = {
      uAge: this.state.uAge,
      uCountry: this.state.uCountry,
      email: this.state.email
    };

    // axios({
    //   url: '/api/users/dashboard',
    //   method: 'POST',
    //   data: user.email
    // }).then

    //  axios.post("/api/users/assessment", newAssessment)
    // .then(this.props.history.push("/dashboard")).catch(err => 
    //  console.log(err))

    this.props.createAssessment(newAssessment, this.props.history)
  }

  render() {
    // const { errors } = this.state;
    const { user } = this.props.auth;

    return (
      <div>
        <UserNavbar />
        <Container>
          <Row>
            <Col sm="12" md={{ size: 6, offset: 3 }}>
                <form onSubmit={this.onSubmit}>
                        <h4 style={{ fontFamily: "Montserrat", "font-size": "40px", "margin-top": "50px"}}>
                          <b>Welcome to Healthynox</b>
                        </h4>
                        <p style={{ fontFamily: "Montserrat", "color":"grey", "font-size": "17px", "margin-top":"15px"}}>
                          Start your mental health journey and register here.
                        </p>
                        <input
                          onChange={this.onChange}
                          // name = 'uAge'
                          // ref={input => this.uAge = input}
                          value={this.state.uAge}
                        //   error={errors.uAge} 
                          id="uAge"
                          placeholder="uAge (Provided by your workplace)"
                          style={{ fontFamily: "Montserrat", "color": "grey", "font-size": "17px", "background-color": "white", "border-radius": "25px", "width": "400px","border": "2rm",
                     "border-style": "solid", "border-color": "black", "display": "inline-block", "padding": "6px 12px"}}
                          type="text"


                        />
                         {/* <span className="red-text">
                          {errors.uAge}
                          {errors.uAgenotfound}
                        </span>  */}

                  <p style={{ fontFamily: "Montserrat", "color": "grey", "font-size": "17px", "margin-top": "25px"}}>Please choose a password (6 or more characters)</p> 
                  <input
                    onChange={this.onChange}
                    value={this.state.uCountry}
                    // error={errors.password}
                    id="uCountry"
                    placeholder="uCountry"
                    style={{ fontFamily: "Montserrat", "color": "grey", "font-size": "17px", "background-color": "white", "border-radius": "25px", "width": "400px","border": "2rm",
                     "border-style": "solid", "border-color": "black", "display": "inline-block", "padding": "6px 12px"}}
                    type="text"
                    // className={classnames("", {
                    //   invalid: errors.password
                    // })} 
                  />

                  <input
                          onChange={this.onChange}

                          value={this.state.email}

                          id="email"
                          placeholder="email (Provided by your workplace)"
                          style={{ fontFamily: "Montserrat", "color": "grey", "font-size": "17px", "background-color": "white", "border-radius": "25px", "width": "400px","border": "2rm",
                     "border-style": "solid", "border-color": "black", "display": "inline-block", "padding": "6px 12px"}}
                          type="text"

                        />

                  {/* <span className="red-text">{errors.password}</span> */}


                    <div>
                      <Button style={{
                            "display": "inline-block",
                            "width": "150px",
                            "borderRadius": "40px",
                            "letterSpacing": "1px",
                            "marginTop": "1rem",
                            "backgroundColor": "blue",
                            "fontFamily": "Montserrat", "color": "white", "font-size": "17px"
                          }} type="submit">
                            Submit
                      </Button>
                    </div>


              </form>
            </Col>
          </Row>
        </Container>


      </div>        

    );
  }
}

AssessmentSimple.propTypes = {
  createAssessment: PropTypes.func.isRequired,
  auth: PropTypes.object.isRequired
//   errors: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  createAssessment: state.createAssessment,
  auth: state.auth
//   errors: state.errors
});

export default connect(
  mapStateToProps,
  { createAssessment }
)(withRouter(AssessmentSimple));
~Dashboard~
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import axios from 'axios';
import { logoutUser } from "../../actions/authActions";

import './Dashboard.css';
import './UserNavbar.js'
import UserNavbar from "./UserNavbar.js";
import { Container, Row, Button, Col } from 'reactstrap';
import {
  Card, CardImg, CardText, CardBody,
  CardTitle, CardSubtitle
} from 'reactstrap';
// import { Button, ButtonToolbar, Modal } from 'react-bootstrap';
import "bootstrap/dist/css/bootstrap.min.css";
import Advance from './Advance.png';
import Assessments from './Assessments.png';
import Mood from './Mood.png';
import Sessions from './Sessions.png'
import Measure from './Measure.png'
import { Redirect } from "react-router-dom";
import Axios from "axios";


class Dashboard extends Component {
  constructor() {
    super();
    this.state = {
     firstLogin: ""
    };
  }

  onLogoutClick = e => {
    e.preventDefault();
    this.props.logoutUser();
  };

  componentDidMount() {
    // axios.get("http://localhost:5000/api/users/dashboard")
    // .then(res => {
    //   const cond = res.data[15].firstLogin;
    //   this.setState({firstLogin: cond });
    // });
    // const firstLogin = this.props.auth.firstLogin;
    if (this.props.auth.firstLogin) {
      this.props.history.push("/dashboard");
    }else{
      this.props.history.push("/assessment");
    }
  }

  render() {
    const { user } = this.props.auth;
    // const data = this.props;

    return (
    <div>
      <UserNavbar/>
      <Container>
        <Row>
          <Col xs="6" sm="4">
            <h4 style={{"marginTop": "80px"}}>
              <b style={{fontSize: "30px", fontFamily: "Montserrat"}}>Hey {user.name}!</b>
              </h4>
              <p className="flow-text grey-text text-darken-1" style={{fontFamily: "Montserrat"}}> 
                  Weclome to Healthynox{" "}
              </p>
              <Button
              style={{
                width: "300px",
                borderRadius: "3px",
                letterSpacing: "1.5px",
                marginTop: "1rem",
                fontFamily: "Montserrat"
              }}
              onClick={this.onSubmitAssessment}
              className="btn btn-large waves-effect waves-light hoverable blue accent-3"
            >
              Launch Short Self-Assessment

           </Button>
          </Col>
        </Row>
        <Row>
          <Col xs="6" sm="4">
              <Card>
              <CardBody>
                <CardTitle>Identify</CardTitle>
                <CardText>Complete assessments regularly to learn more about your state and personality.</CardText>
                <Button color= "primary">Take Assessment</Button>
              </CardBody>
              <CardImg top height= "100px"top width="100%" src={Assessments} alt="Card image cap" />
              </Card>
          </Col>
          <Col xs="6" sm="4">
              <Card>
              <CardBody>
                <CardTitle>Measure</CardTitle>
                <CardText>Monitor and reflect on progress against agreed milestones.</CardText>
                <Button color="primary">View Progress</Button>
              </CardBody>
              <CardImg top height= "100px" top width="100%" src={Measure} alt="Card image cap" />
              </Card>
          </Col>
          <Col xs="6" sm="4">
              <Card>
              <CardBody>
                <CardTitle>Advance</CardTitle>
                <CardText>Work towards your goals by completing tasks set by your personal therapist.</CardText>
                <Button color="primary">Complete Exercise</Button>
              </CardBody>
              <CardImg top height= "100px" top width="100%" src={Advance} alt="Card image cap" />
              </Card>
          </Col>
        </Row>
        <Row>
            <Col xs="6">
             <Card>
              <CardBody>
                <CardTitle>Upcoming Sessions</CardTitle>
                <CardSubtitle>Introductory Session (50 Minutes) on the 30th of April 2020 at 1:00 PM with Sven and Barbara. 
Join Session</CardSubtitle>
                <CardImg top height="100px" top width="100%" src={Sessions} alt="Card image cap" />
                <Button color="primary">Schedule Session</Button>
              </CardBody>
              </Card>
           </Col>
            <Col xs="6">
             <Card>
              <CardBody>
                <CardTitle>Mood Barometer</CardTitle>
                <CardSubtitle>Today I Feel</CardSubtitle>
                <CardImg top height = "100px" top width="20px" src={Mood} alt="Card image cap" />
                <Button color="primary">Send</Button>
              </CardBody>
              </Card>
           </Col>
        </Row>
      </Container>


     </div>
    );
  }
}


Dashboard.propTypes = {
  logoutUser: PropTypes.func.isRequired,
  auth: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  auth: state.auth
});

export default connect(
  mapStateToProps,
  { logoutUser }
)(Dashboard);

来源:https://stackoverflow.com/questions/62365471/how-to-fetch-data-in-react-redux-from-mongoose-mongodb-using-router-to-reflect-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!