useNavigate hook not working in my react app - node.js

I am trying to develop a page where, after registering yourself, you can login with the OTP, which is gonna get through nodemailer module in react.
I have used postman API to test my REST API. It works fine.
But the main the problem is after sending mail, I canbot go to other page.
import "../styles/mix.css";
import { Navigate, NavLink, useNavigate } from "react-router-dom";
import { useState } from "react";
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { sentOtpFunction } from "../services/Apis";
export default function Login() {
const [email,setEmail]=useState("");
const navigate=useNavigate();
//sendOtp
const sendOtp= async (e)=>{
e.preventDefault();
if(email===""){
toast.error("Enter Your Email!");
}
else if(!email.includes('#')){
toast.error("Enter Valid Email!");
}
else{
const data={
email:email
}
const response=await sentOtpFunction(data);
console.log(response);
if(response.status===200){
navigate("/user/otp");
}
else{
toast.error(response.response.data.error)
}
}
}
return (
<>
<section>
<div className="form_data">
<div className="form_heading">
<h1>Welcome Back, Log In</h1>
<p>Hi, we are glad you are back. Please login.</p>
</div>
<form>
<div className="form_input">
<label htmlFor="email">Email</label>
<input type="email" name="email" onChange={(e)=>setEmail(e.target.value)} id="" placeholder="Enter your Email address"></input>
</div>
<button className="btn" onClick={sendOtp}>Login</button>
<p>Don't have an account? <NavLink to="/register">Sign up</NavLink></p>
</form>
</div>
<ToastContainer/>
</section>
</>
)
}
This is sendOtpFunction:
import {commonrequest} from './ApiCall';
import {BACKEND_URL} from './helper';
export const registerfunction=async(data)=>{
return await commonrequest("POST",`${BACKEND_URL}/user/register`,data)
}
export const sentOtpFunction=async (data)=>{
return await commonrequest("POST",`${BACKEND_URL}/user/sendotp`,data)
}
This is my apicall.js:
import axios from 'axios';
export const commonrequest= async(methods,url,body,header)=>{
let config={
method: methods,
url,
headers:header?header:{
"Content-Type":"application/json"
},
data:body
}
//axios Instance
return axios(config).then((data)=>{
return data
}).catch((error)=>{
return error
})
}
This api.js from backend:
require("dotenv").config();
const express=require('express');
const app=express();
const cors=require('cors');
require("./db/conn");
const router=require("./routes/router");
const PORT=4002;
//middleware
app.use(express.json());
app.use(cors());
app.use(router);
app.listen(PORT,()=> console.log("Server connected!!"));
This is routes.js from backend:
const express=require("express");
const router=new express.Router();
const controllers=require("../controllers/userControllers");
// Routes
router.post("/user/register",controllers.userregister);
router.post("/user/sendotp",controllers.userOtpSend);
module.exports=router;
This is usercontrollers file from backend
const users=require("../models/userSchema")
const userotp=require("../models/userOtp");
const nodemailer=require("nodemailer");
//email config
const transporter=nodemailer.createTransport({
service:"gmail",
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth:{
user:process.env.EMAIL,
pass:process.env.PASSWORD
}
})
exports.userregister=async (req,res)=>{
const {fname,email,password}=req.body;
if(!fname||!email||!password){
res.status(400).json({error:"Please Enter All Input Data"});
}
try{
const preuser=await users.findOne({email:email});
if(preuser){
res.status(400).json({error:"This User name is already exist in Our database"})
}
else{
const userregister=new users({
fname,email,password
});
//here password hashing
const storeData=await userregister.save();
res.status(200).json(storeData);
}
}
catch(error){
res.status(400).json({error:"Invalid Details"})
}
}
//user send otp
exports.userOtpSend=async(req,res)=>{
const {email}=req.body;
if(!email){
res.status(400).json({error:"Please Enter Your Email"})
}
try{
const preuser=await users.findOne({email:email});
if(preuser){
const OTP=Math.floor(100000+Math.random()*900000);
const existEmail=await userotp.findOne({email:email});
if(existEmail){
const updateData=await userotp.findByIdAndUpdate({_id:existEmail._id},{
otp:OTP
},{new:true});
await updateData.save();
const mailOptions={
from:process.env.EMAIL,
to:email,
subject:"Sending Email For Otp Validation",
text:`OTP:- ${OTP}`
}
transporter.sendMail(mailOptions,(error,info)=>{
if(error){
console.log("error",error);
res.status(400).json({error:"email not send"});
}
else{
console.log("Email sent",info.response);
res.status()
}
})
}
else{
const saveOtpData=new userotp({
email,otp:OTP
});
await saveOtpData.save();
}
}
else{
res.status(400).json({error:"This User not exist in our Database"});
}
}
catch(error){
res.status(400).json({error:"Invalid Details",error})
}
}

Most probably the issue would be the lack of status code in the response after sending the email:
// backend ../controllers/userControllers
console.log("Email sent",info.response);
res.status()
...whereas you expect a 200 code to trigger page navigation:
// Front Login
if(response.status===200){
navigate("/user/otp");
}
That being said, just res.status() is strange in itself. You probably meant res.send() to properly terminate the handling, Express using 200 status code by default.
Furthermore, by default Axios treats status codes outside the 2xx range as an error (see validateStatus config option). You handle that error in your catch, but silently return the error object, which is not directly the response (but it still holds it in error.response).

Related

Uploading files from React to Node - cannot access File object

I'm struggling to access the FileList from an input type="file" submitted from a React frontend to a Node backend. From my browser console I can see that the desired list of files is being submitted as the form data.
Eventually worked out that the FileList looks like an array but isn't! So got the length of it using Object.keys (interestingly other answers recommended here didn't work for me).
But no matter what I try I can't access the individual File objects... I can now cycle through the items in the FileList but I need to be able to get the filename to upload/move it to a new location on my server. It looks like they're empty objects in node but the browser is showing that it's sending the information I need.
Why are the objects I am iterating through empty?
I'm stumped.
Thanks for your help!
Browser Console Output
Node.js
router.post("", (req, res) => {
var tempFiles = req.body.files;
var fileCount = Object.keys(tempFiles).length;
console.log("FileList Keys: " + Object.keys(tempFiles));
console.log("Length: " + Object.keys(tempFiles).length);
console.log("Object Length: " + Object.keys(tempFiles['0']).length);
// Loop through files
for (let i = 0; i < fileCount; i++) {
let file = tempFiles[i];
console.log(tempFiles[i]);
}
}
Node console output:
FileList Keys: 0,1
Length: 2
Object Length: 0
{}
{}
React Form
import React from 'react';
import axios from 'axios';
import {useState} from 'react';
import { useForm } from "react-hook-form";
import { Stack, Input ,InputRightElement, InputGroup, Button, FormControl, FormLabel, FormHelperText, Checkbox, Radio, RadioGroup } from '#chakra-ui/react';
import BasicBanner from '../../core/components/banners/BasicBanner';
export default function UploadEvidence(props) {
const [data, setData] = useState("");
const [formMessage, setFormMessage] = useState("");
const { register, formState: { errors }, handleSubmit } = useForm();
const onError = (errors, e) => console.log(errors, e);
const onSubmit = (data, e) => {
console.log(data);
axios.post('http://localhost:5000/api/uploads', data)
.then(function (response) {
console.log(response);
setFormMessage("Upload successful");
})
.catch(function (error) {
console.log(error);
setFormMessage("Error uploading");
});
}
return (
<form onSubmit={handleSubmit(onSubmit, onError)} enctype="multipart/form-data">
<Stack spacing="10">
{formMessage &&
<BasicBanner message={formMessage} />
}
<Input
type="file"
accept="pdf/*"
multiple
{...register("files", {required: true })}
aria-invalid={errors.active ? "true" : "false"}
/>
</Stack>
<FormControl mt={4}>
<Button type="submit" colorScheme='blue'>Save</Button>
</FormControl>
</form>
)
}
Node server.js
const express = require('express')
const PORT = process.env.PORT || 5000
const app = express()
const bodyParser = require("body-parser");
const fileupload = require("express-fileupload");
var cors = require('cors');
app.use(cors());
app.use(fileupload());
app.use(express.static("files"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
... Routes ...

OAuth2 authorization - how do I get around cors?

I am trying to obtain user tokens from the mavenlink API, docs here, I am currently sending a get request from the client side app to the backend (node.js server) which then sends a get request to the mavenlink API with the required parameters in the url.
The desired outcome is when the user clicks the button on client side a new window opens with the mavenlink OAuth login page, then once user has logged in and authorised the application from their account in mavenlink it redirects to the designated redirect_uri and has a code in the url which then needs to be sent off in post request.
However issue is I get to the point where window is opened but whenever I try to login it gives error "cannot post / login", rather than redirecting to a url.
I am using a get request to the server, which then triggers a get request from the server to the API to get arounds the cors error/issue. But when I tested the url I am using in the get request from the server, by just pasting it into my browser, it worked fine and I could authorize the app.
So I am guessing it needs to work by coming from the client side? but how is that possible? or does it need to go from server side and I am doing it wrong?
Code below.
Client side API call:
import { Button, Container, Grid, Paper } from '#mui/material';
import React, {useEffect, useState} from 'react';
import { getAuth } from "firebase/auth";
import axios from 'axios';
import {db} from '../firebase';
import { doc, getDoc, } from 'firebase/firestore'
import '../styles/modules/mavenlinkPage.scss';
import Fab from '#mui/material/Fab';
import AddIcon from '#mui/icons-material/Add';
import {SuccessSnackbar, ErrorSnackbar} from '../components/PopupSnackbar';
export const MavenlinkPage = () => {
const auth = getAuth();
const user = auth.currentUser;
const [apiData, setApiData] = useState([]);
const [tokenResponse, setTokenResponse] = useState([]);
const [oauthToken, setOauthToken] = useState("");
const [secretToken, setSecretToken] = useState("");
const [clientId, setClientId] = useState("");
const [accessCode, setAccessCode] = useState("");
const [mavenlinkConnected, setMavenlinkConnected] = useState(false);
const [errorAlert, setErrorAlert] = useState(false);
const [successAlert, setSuccessAlert] = useState(false);
//Destructuring the objects that contain relevant keys for firestore db that we got in useEffect below
const {token, secret_token} = secretToken;
const {id, client_id} = clientId;
const handleAlertClose = (event, reason) => {
if (reason === 'clickaway') {
return;
}
setSuccessAlert(false) && setErrorAlert(false);
};
//Function to retrieve the oauth token for mavenlink stored in firebase database
const getToken = async () => {
const docRefOauth = doc(db, 'mavenlink', 'oauth');
const docRefToken = doc(db, 'mavenlink', 'secret_token');
const docRefClientId = doc(db, 'mavenlink', 'application_id');
const docOauth = await getDoc(docRefOauth);
const docToken = await getDoc(docRefToken);
const docClientId = await getDoc(docRefClientId);
if (docOauth.exists() && docToken.exists() && docClientId.exists()) {
setOauthToken(docOauth.data())
setSecretToken(docToken.data())
setClientId(docClientId.data())
} else {
console.log("error: no document")
}
}
const getAuthorization = () => {
console.log(id);
console.log(token);
axios({
method: 'get',
url: 'http://localhost:5000/oauth/authorize',
data: {}
})
.then((response) => {
window.open('http://localhost:5000/oauth/authorize', 'Mavenlink')
})
}
useEffect(() => {
getToken();
}, [])
return(
<>
<Container>
<div className="mavenlink-page">
<Grid container spacing={2}>
<Grid item xs={12}>
<h1>Mavenlink</h1>
</Grid>
<Grid item xs={12}>
<Paper className="connection-status" elevation={1}>
<h4 className="title">Connection Status:</h4>
{!mavenlinkConnected ? <h4 className="response-error">{user.email} is not connected</h4> : <h4 className="response-success">{user.email} is connected</h4>}
</Paper>
</Grid>
<Grid item xs={6}>
<Paper elevation={1}>
<h4>Sync account to mavenlink API?</h4>
<Fab onClick={getData} color="primary" aria-label="add">
<AddIcon />
</Fab>
</Paper>
</Grid>
<Grid item xs={6}>
<Paper elevation={1}>
<h4>*Test User Token</h4>
<Fab onClick={getAuthorization} color="warning" aria-label="add">
<AddIcon />
</Fab>
</Paper>
</Grid>
{/* <Button onClick={getData}>Test API</Button> */}
</Grid>
</div>
{successAlert === true ? <SuccessSnackbar open={successAlert} handleClose={handleAlertClose}/> : <></> }
{errorAlert === true ? <ErrorSnackbar open={errorAlert} handleClose={handleAlertClose}/> : <></> }
</Container>
</>
);
};
server side:
const { default: axios } = require('axios');
const router = require('express').Router();
require('dotenv').config();
const mavenlink_app_id = process.env.MAVENLINK_APP_ID;
const secret_token_mavenlink = process.env.SECRET_TOKEN_MAVENLINK;
router.get('/oauth/authorize', (req, res) => {
axios({url:'https://app.mavenlink.com/oauth/authorize?client_id='+mavenlink_app_id+'&response_type=code&redirect_uri=http://localhost:5000/oauth/callback',})
.then((response) => {
console.log(response.data)
res.send(response.data)
})
.catch(error => console.log(error));
})
router.get('/oauth/callback', (req, res) => {
try {
let returnTo = req.protocol +'://'+req.hostname;
const port = req.connection.localPort
if (port !== undefined && port !== 5000) {
returnTo = `${returnTo}:3000`;
}
let access_token = req.query.code;
console.log(access_token)
res.status(201)
.cookie('mavenlink_token', access_token, {
expires: new Date(Date.now() + 120000), // cookie will be removed after 2 minutes
})
.redirect(301, `${returnTo}/`)
} catch(error) {
res.status(500).send('Server Error')
}
})
module.exports = router;
Why do you need your server to proxy request to mavenlink? This seems to be the issue as the mavenlink login form seems to be posting back to your server. Why can't your server just redirect the browser to mavenlink url instead?
If you open a window with a URL http://localhost:5000/oauth/authorize, your server will redirect to mavenlink and the login form will submit to mavenlink and the redirect will come back to your server at http://localhost:3000/mavenlinkpage with the auth code.

I am trying to display data from an external API, how can I fix the issue in my code?

This is the error message I am getting
TypeError: undefined is not an object (evaluating 'drinkList.drinks[0]')
How can I fix the error so that I can use the app to fetch data from the external api?
This is my drink.js code:
import React, { useEffect, useState } from "react";
import axios from "axios";
import Drinks from "./Drinks";
function Home() {
const [drinkName, setDrinkName]= useState([]);
const [drinkList, setDrinkList] = useState([]);
const drinksURL = `https://www.thecocktaildb.com/api/json/v1/1/search.php?s=${drinkName}`;
const handleChangeDrink= e => {
setDrinkName(e.target.value);
}
const getDrink = () => {
axios
.get(drinksURL)
.then(function (response) {
setDrinkList(response.data);
console.log(drinksURL);
})
.catch(function (error) {
console.warn(error);
});
};
return (
<main className="App">
<section className="drinks-section">
<input
type="text"
placeholder="Name of drink (e.g. margarita)"
onChange={handleChangeDrink}
/>
<button onClick={getDrink}>Get a Drink Recipe</button>
<Drinks drinkList={drinkList} />
</section>
</main>
);
}
export default Home;
This is my Drink.js code:
import React from "react";
function Drinks({ drinkList }) {
if (!drinkList) return <></>;
return (
<section className="drinkCard">
<h1>{drinkList.drinks[0].strDrink}</h1>
</section>
);
}
export default Drinks;
Couple of problems here...
drinkName is initialised as an array but it appears to be expecting a string
drinkList is initialised as an array but the data from the API is an object. You may want to assign the drinks array from the response instead
drinksUrl is never updated
An empty array is still truthy
Some easy fixes
const [drinkName, setDrinkName]= useState(null) // initialise as null
const [drinkList, setDrinkList] = useState([])
// don't include the "s" parameter here
const drinksURL = "https://www.thecocktaildb.com/api/json/v1/1/search.php"
const getDrink = () => {
// pass drinkName as a param
axios.get(drinksURL, {
params: { s: drinkName }
}).then(res => {
// note that we're extracting `drinks`
setDrinkList(res.data.drinks)
}).catch(console.warn)
}
and in Drink.js
function Drinks({ drinkList }) {
// check the array length
return drinkList.length && (
<section className="drinkCard">
<h1>{drinkList[0].strDrink}</h1>
</section>
)
}

ReactJS Stripe Payments not returning successful message after clicking pay with node and express

I am currently using ReactJS, node, and express with the Stripe Payment API. After clicking the pay button and entering the dummy credit card credentials, the page doesnt process the payment. I have entered the correct publishing key and api key that I got from my dashboard.I believe it likely has somnething to do with what I need to add in the server.js file(aka node backend).I have read through the docs for any clues I can get. Also have searched here on Stack Overflow. None of the questions had the same thing I was looking for. Please see below for pictures and code. Thanks
This is before pressing the button. Please Note the console on the right side.
This is after pressing the button. The loading spinner just displays forever. Also note the console on right side
// Donate.js
import React from "react";
import "./Donate.css";
import { loadStripe } from "#stripe/stripe-js";
import { Elements } from "#stripe/react-stripe-js";
import CheckoutForm from "./CheckoutForm";
// Make sure to call `loadStripe` outside of a component’s render to avoid
// recreating the `Stripe` object on every render.
const stripe = loadStripe(
"pk*****************************"
);
stripe.then((data) => {
console.log(data);
});
const Donate = () => {
return (
<div className="donate">
<h1 className="donate__sectionHeader">Donate Now</h1>
<Elements stripe={stripe}>
<CheckoutForm />
</Elements>
</div>
);
};
export default Donate;
//CheckoutForm
import React, { useState, useEffect } from "react";
import { CardElement, useStripe, useElements } from "#stripe/react-stripe-js";
import "./CheckoutForm.css";
export default function CheckoutForm() {
const [succeeded, setSucceeded] = useState(false);
const [error, setError] = useState(null);
const [processing, setProcessing] = useState("");
const [disabled, setDisabled] = useState(true);
const [clientSecret, setClientSecret] = useState("");
const stripe = useStripe();
const elements = useElements();
useEffect(() => {
// Create PaymentIntent as soon as the page loads
window
.fetch("/donate", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({ items: [{ id: "xl-tshirt" }] }),
})
.then((res) => {
return res.json();
})
.then((data) => {
setClientSecret(data.clientSecret);
});
}, []);
const cardStyle = {
style: {
base: {
color: "#32325d",
fontFamily: "Arial, sans-serif",
fontSmoothing: "antialiased",
fontSize: "16px",
"::placeholder": {
color: "#32325d",
},
},
invalid: {
color: "#fa755a",
iconColor: "#fa755a",
},
},
};
const handleChange = async (event) => {
// Listen for changes in the CardElement
// and display any errors as the customer types their card details
setDisabled(event.empty);
setError(event.error ? event.error.message : "");
};
const handleSubmit = async (ev) => {
ev.preventDefault();
setProcessing(true);
const payload = await stripe.confirmCardPayment(clientSecret, {
payment_method: {
card: elements.getElement(CardElement),
},
});
if (payload.error) {
setError(`Payment failed ${payload.error.message}`);
setProcessing(false);
} else {
setError(null);
setProcessing(false);
setSucceeded(true);
}
console.log(clientSecret);
};
return (
<form id="payment-form" onSubmit={handleSubmit}>
<CardElement
id="card-element"
options={{ hidePostalCode: true, cardStyle }}
onChange={handleChange}
/>
<button disabled={processing || disabled || succeeded} id="submit">
<span id="button-text">
{processing ? <div className="spinner" id="spinner"></div> : "Pay"}
</span>
</button>
{/* Show any error that happens when processing the payment */}
{error && (
<div className="card-error" role="alert">
{error}
</div>
)}
{/* Show a success message upon completion */}
<p className={succeeded ? "result-message" : "result-message hidden"}>
Payment succeeded, see the result in your
<a href={`https://dashboard.stripe.com/test/payments`}>
{" "}
Stripe dashboard.
</a>{" "}
Refresh the page to pay again.
</p>
</form>
);
}
//server.js
const express = require("express");
const app = express();
const { resolve } = require("path");
// This is your real test secret API key.
const stripe = require("stripe")(
"sk_test_**********************************"
);
app.use(express.static("."));
app.use(express.json());
const calculateOrderAmount = (items) => {
// Replace this constant with a calculation of the order's amount
// Calculate the order total on the server to prevent
// people from directly manipulating the amount on the client
return 1400;
};
app.post("/create-payment-intent", async (req, res) => {
const { items } = req.body;
// Create a PaymentIntent with the order amount and currency
const paymentIntent = await stripe.paymentIntents.create({
amount: 1099,
currency: "usd",
// Verify your integration in this guide by including this parameter
metadata: { integration_check: "accept_a_payment" },
});
res.send({
clientSecret: paymentIntent.client_secret,
});
});
app.listen(4242, () => console.log("Node server listening on port 4242!"));
You need to review the server call/network response with the client_secret. The console error indicates you've provided an invalid secret to confirmCardPayment, apparently an empty string.
You specified: .
It would appear that your app is not setting the state via setClientSecret as intended, and you end up with the initial empty string value from useState("");.
Check your client_secret value before the confirmCardPayment call, and step backwards to find where the value is being dropped.

Cannot redirect to new page on first submission of form with history.push()

Edit
I've done some more debugging and here is the problem:
CreateProfile.js calls profileActions.createProfile() and passes data to be operated on and this.props.history so that it can push a new path onto the history stack.
profileActions.createProfile() successfully sends data to database. Database successfully uses the data.
profileActions.createProfile() pushes new path onto stack. The component at the path loads and successfully calls a reducer.
The URL in the browser does not reflect the path that is pushed onto the history stack. The new component does not load.
This only happens when creating an entry in the database. When updating an entry, the program works as expected.
I'm currently trying to redirect to a new page with react/redux. On the first submission, the form submits to the backend and creates an entry in the database but fails to redirect to the next page. On the second submission, however, it redirects just fine.
I'm using this.props.history.push() to do the redirect.
I think It may be an issue with the the response received from the backend but I cannot seem to figure out what the issue is. The reason I believe this is because it is hitting different logic because on the second submission, it is updating and not creating an entry.
Here is my component (CreateProfile.js)
import React, { Component } from 'react'
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { createProfile } from '../../actions/profileActions';
import TextAreaGroup from '../common/TextAreaGroup';
import InputGroup from '../common/InputGroup';
class CreateProfile extends Component {
// Constructor
// componentWillRecieveProps()
onSubmit = (evt) => {
evt.preventDefault();
const profileData = {
handle: this.state.handle,
bio: this.state.bio,
website: this.state.website,
twitter: this.state.twitter,
instagram: this.state.instagram,
youtube: this.state.youtube,
linkedin: this.state.linkedin,
github: this.state.github,
vsco: this.state.vsco
};
this.props.createProfile(profileData, this.props.history);
}
//onChange()
render() {
// render logic
return (
// markup
<form onSubmit={this.onSubmit}>
// markup
<input
type="submit"
value="Create Profile"
className="btn btn-info btn-block mt-4"
/>
</form>
</div>
</div>
</div>
</div>
)
}
}
CreateProfile.propTypes = {
createProfile: PropTypes.func.isRequired,
profile: PropTypes.object.isRequired,
errors: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
profile: state.profile,
errors: state.errors
});
export default connect(mapStateToProps, { createProfile })(withRouter(CreateProfile));
Here is my action file that submits to the backend (profileActions.js):
import axios from 'axios';
// import types
import { GET_PROFILE, PROFILE_LOADING, GET_ERRORS, CLEAR_CURRENT_PROFILE } from './types';
// Create Profile
export const createProfile = (profileData, history) => dispatch => {
axios.post('/api/profile', profileData)
.then(res => history.push('/login'))
.catch(err => {
dispatch({
type: GET_ERRORS,
payload: err.response.data
})
})
};
}
And here is the route in my backend that is being submitted to:
router.post('/', passport.authenticate('jwt', { session: false }), (req, res) => {
const { errors, isValid } = validateProfileInputs(req.body);
if (!isValid) {
return res.status(400).json(errors);
}
const profileFields = {}; //code setting fields omitted
Profile.findOne({user: req.user.id}).then(profile => {
if (profile) {
// Update Profile
Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFields },
{ new: true }
).then(profile => res.json(profile)); // SUCCESSFUL PUSH ONTO THIS.PROPS.HISTORY
} else {
// Create Profile
// Check if handle exists
Profile.findOne({ handle: profileFields.handle })
.then(profile => {
if (profile) {
errors.handle = 'That handle already exists';
res.status(400).json(errors);
}
new Profile(profileFields).save().then(profile => res.json(profile)); // PUSH ONTO THIS.PROPS.HISTORY NOT OCCURRING
});
}
});
});
Any and all help would be greatly appreciated. I have tried my hardest but cannot seem to figure out what the issue is.
This problem arose because of my lack of understanding of how asynchronous javascript works.
The issue was with a few lines of code in the component that I was trying to push too.
componentDidMount() {
this.props.getProfile(); // Async function, sets profile object in store
}
render() {
const { profile } = this.state.profile;
if(!Object.keys(profile).length > 0) { // This is always evaluates to true
// because it executes before
// this.props.getProfile() returns
this.props.history.push('/create-profile');
}
}

Resources