React function doesn't work when placed inside another function - reactjs

In the frontend I've made 2 buttons, one to create the data from a form and another the GET and display it onto the frontend, this is all being sent and received from an API and it works just fine when I use two separate buttons. What I want to do is combine the two to function only when the create button is clicked; I've tried putting the getData function into the createData function but it never works and I keep on getting errors.
How can I fix this?
Frontend.js
import React, { useState, useRef, useEffect } from 'react';
import axios from 'axios'
import './App.css';
function App() {
const cardHolderRef = useRef("");
const balanceRef = useRef("");
const [cardHolder, setCardHolder] = useState("");
const [cardNumber, setCardNumber] = useState("");
const [balance, setBalance] = useState("");
const [expDate, setExpDate] = useState("");
const [cvc, setCvc] = useState("");
async function getCardData() {
await axios.get("http://localhost:5000/", { crossdomain: true })
.then(response => {
setCardHolder(response.data.data.name_on_card);
setCardNumber(response.data.data.card_pan);
setBalance(response.data.data.amount + " " + response.data.data.currency);
setExpDate(response.data.data.expiration);
setCvc(response.data.data.cvv);
})
};
async function createCardData(e) {
e.preventDefault();
await axios.post("http://localhost:5000/", {
cardHolder: cardHolderRef.current.value,
balance: balanceRef.current.value
})
getCardData();// This isn't working at all
};
return (
<div>
<div className='vcard'>
<div className='theBalance'>
<h2>{balance}</h2>
</div>
<div className='numNcvc'>
<h2 className='theNum'>{cardNumber}</h2>
<h2 className='theCvc'>{cvc}</h2>
</div>
<div className='expNholder'>
<h2>Expiry Date<br/> {expDate}</h2>
<h2>Card Holder<br/> {cardHolder}</h2>
</div>
</div>
<div className='details-div'>
<form className='details'>
<input
placeholder='Name on Card'
type="text"
id='cardholder'
name='cardholder'
ref={cardHolderRef}></input>
<input
placeholder='Amount (in USD)'
type="text"
id="cardbalance"
name="cardbalance"
ref={balanceRef}></input>
<input placeholder='MTN MoMo Number' type="text"></input>
</form>
<button className='createCardBtn' onClick={createCardData}>
Create Card
</button>
<button className='createCardBtn' onClick={getCardData}>
Get Card Data
</button>
</div>
</div>
);
}
export default App;
Backend.js
const { response } = require('express');
const express = require('express');
const cors = require('cors');
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
const jsonParser = bodyParser.json();
const Flutterwave = require('flutterwave-node-v3');
const flw = new Flutterwave("FLWPUBK_TEST-63a79c5a6fe457d75a611b0f376e3e53-X", "FLWSECK_TEST-a6281194ef4ca095e794a1681fe32d69-X");
app.use(bodyParser.json());
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.post("/", jsonParser, async (req, res) => {
const cardHolder = req.body.cardHolder;
const balance = req.body.balance;
console.log(cardHolder);
console.log(balance);
// Payload: Flutterwave Card Details
const payload = {
"currency": "USD",
"amount": balance,
"billing_name": cardHolder,
"billing_address": "2014 Forest Hills Drive",
"billing_city": "React",
"billing_state": "NY",
"billing_postal_code": "000009",
"billing_country": "US",
}
const createCardResponse = await flw.VirtualCard.create(payload);
const newPayload = {
"id": createCardResponse.data.id
}
const fetchResponse = await flw.VirtualCard.fetch(newPayload);
console.log(fetchResponse);
app.get('/', async (req, res) => {
res.send(fetchResponse);
})
});
app.use(bodyParser.json());
app.listen(5000, () => {console.log("Server started on port 5000")})
//createVcard();

In the api response, you added the app.get method inside the app.post, and you aren't returning any data.
You need to move the app.get outside the app.post and in the app.post return your data like this:
app.get('/', async (req, res) => {
...
}
app.post("/", jsonParser, async (req, res) => {
const cardHolder = req.body.cardHolder;
....
const fetchResponse = await flw.VirtualCard.fetch(newPayload);
res.send(fetchResponse);
});

Related

How can we receive a csv file in server side react hooks web app

In react hooks web app, how can we receive a csv file in the server side. The below is not working as I am getting the file undefined in server side. Could someone please advise ?
server.js
const multer = require('multer');
const bodyParser = require("body-parser");
const path = require('path');
app.use(express.static(path.join(__dirname, 'public')));
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/csv')
},
filename: function (req, file, cb) {
var ext = file.originalname.split('.').pop();
cb(null, file.fieldname + '-' + Date.now() + '.' + ext);
}
})
var upload = multer({ storage: storage });
app.put('/service/managenominees', upload.single('file'), async (req, res, next) => {
// csv file has two columns named Name, Email, I would like to receive value from those..
const data = req.file;
try {
if(req.body.file){
var name = req.file.Name;
var email = req.file.Email;
}
var nomineeData = {userName: name, userEmail: email};
res.status(200).send(nomineeData);
} catch (e) {
res.status(500).json({ fail: e.message });
}
});
manageNominee.js
import React, { useRef, useEffect, useState } from "react";
import Axios from "axios";
const ManageNominees = () => {
const [uploadFile, setUploadFile] = React.useState();
const [csvData, setCsvData] = useState([]);
const onChangeCsv = (e) => {
setCsvData(e.target.files[0]);
}
const submitForm = (data) => {
const dataArray = new FormData();
dataArray.append("uploadFile", data);
Axios.put("http://localhost:8000/service/managenominees", dataArray, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then((response) => {
// successfully uploaded response
})
.catch((error) => {
// error response
});
};
return (
<div>
<form onSubmit={submitForm} encType="multipart/form-data">
<h1>Upload Data</h1>
<input type="file" name="csvfile" onChange={onChangeCsv}/>
<button>Submit</button>
</form>
</div>
)
}
export default ManageNominees
There are two issues:
HTML attribute and the mutler upload option are different.
File values cant be accessed directly either convert the buffer and read the content or read the file (below code reads the file).
const multer = require('multer');
const bodyParser = require("body-parser");
const path = require('path');
const csv = require('csv-parser');
const fs = require('fs');
...
app.put('/service/managenominees', upload.single('csvfile'), (req, res, next) => {
console.log(req.file);
fs.createReadStream(req.file.path)
.pipe(csv())
.on('data', (data) => results.push(data))
.on('end', () => {
console.log(results);
// Result would be array as its CSV, iterate over the array and to get username and email id.
res.status(200).send(results);
});
});
Note: Code does not handle if the file does not exist.

Issue fetching data with react

I have a rare issue fetching data on a useEffect hook....It gives me "CORS error" on chrome inspector... here is my code:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './HomeScreen.css'
import config from '../config'
// Compomnents
import Quiz from "../components/Quiz";
const HomeScreen = () => {
const [data, setData] = useState({ quizzes: [] });
const [loading, setLoading] = useState('true');
const [error, setError] = useState(false);
console.log("TESTING...............................");
useEffect(() => {
setLoading('testing');
const url = "https://mocki.io/v1/4a0ad1a9-352a-45bb-84b9-67e6363d6b7a"; //config.prodLocalhostURLRestAPI + 'quizzes';
fetch(url)
.then(res => res.json())
.then(res => {
setLoading('result..........')
})
.catch(error => {
//console.log(error);
});
}, []);
return (
<div className="homescreen">
<h2 className="homescreen__title">Quizzes</h2>
<div className="homescreen__quizzes">
<h2>{loading}</h2>
{loading ? <h2>Loading............</h2> : error ? <h2>ERROR</h2> : data.quizzes.map(quiz => (
<Quiz />
))}
</div>
</div>
)
}
export default HomeScreen;
The server code is:
var express = require("express"),
app = express(),
http = require("http"),
bodyParser = require("body-parser"),
methodOverride = require("method-override"),
server = http.createServer(app),
mongoose = require("mongoose");
const port = process.env.OPENSHIFT_NODEJS_PORT || 3011;
app.set('port', port);
app.set('ipaddr', process.env.OPENSHIFT_NODEJS_IP || "127.0.0.1");
app.use(bodyParser.json());
app.use(methodOverride());
//Import routes
const chatsRoutes = require('./routes/quizzes');
app.use('/quizzes/', chatsRoutes);
app.get('/', (req, res) => {
res.send("Ready!");
});
/** catch 404 and forward to error handler */
app.use('*', (req, res) => {
return res.status(404).json({
success: false,
message: 'API endpoint doesnt exist'
})
});
//app.use('/', routesRaids);
mongoose.connect('mongodb://localhost/quizes', {useNewUrlParser: true, useUnifiedTopology: true }, () =>
console.log('Connected to Mongo DB')
);
app.listen(port);
The URL is correct and works directly on the browser.
What's the issue?
First hit npm install cors , then
var express = require("express"),
app = express(),
http = require("http"),
bodyParser = require("body-parser"),
methodOverride = require("method-override"),
server = http.createServer(app),
mongoose = require("mongoose");
const cors = require('cors');
const port = process.env.OPENSHIFT_NODEJS_PORT || 3011;
app.use(cors())
app.set('port', port);
app.set('ipaddr', process.env.OPENSHIFT_NODEJS_IP || "127.0.0.1");
app.use(bodyParser.json());
app.use(methodOverride());
//Import routes
const chatsRoutes = require('./routes/quizzes');
app.use('/quizzes/', chatsRoutes);
app.get('/', (req, res) => {
res.send("Ready!");
});
/** catch 404 and forward to error handler */
app.use('*', (req, res) => {
return res.status(404).json({
success: false,
message: 'API endpoint doesnt exist'
})
});
//app.use('/', routesRaids);
mongoose.connect('mongodb://localhost/quizes', {useNewUrlParser: true, useUnifiedTopology: true }, () =>
console.log('Connected to Mongo DB')
);
app.listen(port);

How to send a form input data containing both image and text from React front-end to Express backend using Multer

When I test sending a request containing both image and text grabbbed from user, it comes through to the backend with proper data when I use Postman. Not from React front-end, though. Request does come through but req.body seems to be empty when I console.log it from backend. What am I doing wrong? I am using Multer.
//FRONT-END
import React, { useState } from 'react';
import axios from 'axios';
const ListProperty = (props) => {
const [address, setAddress] = useState('');
const [file, setFile] = useState(null);
const [filename, setFilename] = useState('Choose File');
const handleAddressChange = (evt) => {
setAddress(evt.target.value);
};
const handlePhotoSelect = (evt) => {
setFile(evt.target.files[0]);
setFilename(evt.target.files[0].name);
};
const handleSubmit = async (evt) => {
evt.preventDefault();
const formData = new FormData();
formData.append('address', address);
formData.append('upload', file);
console.log(formData);
try {
axios.post('http://localhost:3000/listproperty', {
headers: { 'Content-Type': 'multipart/form-data' },
body: formData,
});
} catch (err) {
console.log(err);
}
};
return (
<div>
<h2>Property Listing Form</h2>
<span>Provide property address and Photo</span>
<form onSubmit={handleSubmit}>
<input
type="text"
value={address}
onChange={handleAddressChange}
name={address}
placeholder="Enter address"
/>
<br />
<input type="file" onChange={handlePhotoSelect} />
<button>Click to list</button>
</form>
</div>
);
};
export default ListProperty;
//BACK-END
const express = require('express');
const PropertyModel = require('../models/propertyModel');
const router = new express.Router();
const UserModel = require('../models/userModel');
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/images');
},
filename: function (req, file, cb) {
const uniqueName = `${Math.random().toString(32).slice(2)}.jpg`;
req.image = uniqueName;
cb(null, uniqueName);
},
});
const upload = multer({ storage });
router.post(
'/listproperty',
upload.single('upload'),
async (req, res) => {
console.log('hitting Backend router');
const property = new PropertyModel({
...req.body,
owner: req.user._id,
photo: req.image,
});
await UserModel.findByIdAndUpdate(req.user._id, {
$push: { properties: property._id },
});
try {
await property.save();
res.status(200).send(property);
} catch (err) {
console.log(err);
res.status(400).send(err);
}
}
);
module.exports = router;
If you are sending form data in the body you need to use the formidable npm module
you can install it using npm i formidable
then require formidable at top of the file
var formidable = require("formidable");
router.post(
'/listproperty',
upload.single('upload'),
async (req, res) => {
var form = new formidable.IncomingForm();
form.multiples = false;
form.parse(req, async function (err, fields, files) {
/**now here you can get all files in files and fields with fields
in your case you have sent
formData.append('address', address);
formData.append('upload', file);
above two data in form
so you can get your image from files.upload
and address fields.address **/
})
})
In addition, I would suggest you use Axios for api calls
your axios request is not right. axios post request accepts data as a second argument and third argument is for options ( headers etc ),
axios.post('http://localhost:3000/listproperty', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
another thing is your request is not being triggered at all. try setting input type to submit instead of using the button to trigger onSubmit handler of the form.
<form onSubmit={handleSubmit}>
<input
type="text"
value={address}
onChange={handleAddressChange}
name={address}
placeholder="Enter address"
/>
<br />
<input type="file" onChange={handlePhotoSelect} />
<input type="submit" value="Submit" />
</form>

Uploading Image file to Mongodb creates an empty item. React JS

I am currently developing a web app in React JS using a mongodb database to upload data. I am trying to upload image files to the database but the items show up empty. How would I fix this problem?
Backend code for uploading data
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const multer = require('multer');
const GridFsStorage = require('multer-gridfs-storage');
const url = "mongodb://localhost:27017/StudyAppDB";
const storage = new GridFsStorage({ url });
const upload = multer({ storage });
const app = express();
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
mongoose.connect("mongodb://localhost:27017/StudyAppDB", {useNewUrlParser: true, useUnifiedTopology: true});
const imageSchema = {
key: String,
file: {
name: String,
lastModified: Number,
lastModifiedDate: String,
size: Number,
type: String,
webkitRelativePath: String,
},
filename: String,
}
const Images = mongoose.model("Images", imageSchema);
app.post('/uploadfile', upload.single('avatar'), (req, res) => {
const newImages = new Images(
req.body.data
)
newImages.save(function (err) {
if (!err) {
res.send("saved");
} else {
res.send(err);
}
});
})
app.listen(5000, function (req, res) {
console.log("listening");
})
Frontend code for collecting data:
fileUploadHandler is the function that uploads data to the database.
import React, {useState} from 'react';
import './Feed.css';
import axios from 'axios';
const multer = require('multer');
const GridFsStorage = require('multer-gridfs-storage');
const url = "mongodb://localhost:27017/StudyAppDB";
// Create a storage object with a given configuration
const storage = new GridFsStorage({ url });
// Set multer storage engine to the newly created object
const upload = multer({ storage });
export default function PostForm(props) {
const [selectedFile, setSelectedFile] = useState(null)
function fileSelectedHandler(event) {
setSelectedFile(event.target.files[0])
}
function fileUploadHandler(){
// Create an object of formData
const formData = new FormData();
// Update the formData object
formData.append(
"myFile",
selectedFile,
selectedFile.name
);
axios.post("uploadfile", upload.single('avatar'), {data: formData})
.then(function (response) {
//after submitting go to calendar page or whatever
})
.catch(function (error) {
console.log(error);
});
}
return (
<div className="post-form">
<form onSubmit={handleSubmit} style={{width: '99%'}}>
Category:
<div>
<select style={{width: '15%', padding: '0.2%', marginTop: '1%'}} value={category} onChange={(e) => setCategory(e.target.value)}>
{props.categories.map((category, index) =>
<option key={category} value={category}>{category}</option>
)}
</select>
</div>
<br/>
<div style={{textAlign:'center'}}><textarea className='newContentText' value={content} onChange={e => setContent(e.target.value)}/> </div>
<input type="file" onChange={fileSelectedHandler}/>
<button onClick={fileUploadHandler}>Upload</button>
<button className="postButton">Post</button>
</form>
</div>
)
}

React form data isn't being sent to express backend

I've followed several tutorials and SO posts, but I'm having issues sending data from a React form to the backend. I've tried both fetch and axios and nothing seems to be working. I've checked the network tab and can see that the request has been sent to the correct URL and it has returned a 200 code - but nothing is being logged in the back end.
App.js
// Require modules
const express = require("express");
const mongoose = require("mongoose");
const session = require("express-session");
var cors = require('cors');
const app = express();
app.use(cors());
// Set up
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
const port = 5000;
// Mongoose
mongoose.connect("mongodb+srv://georgegilliland:94AJK6OlK5vasVOn#george-cluster-jjfzz.mongodb.net/DPFootball?retryWrites=true&w=majority", {useNewUrlParser: true}, ()=>{
console.log("DB connected")
});
// Controllers
let login = require('./controllers/login');
app.use('/api/login', function (req, res) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader('Access-Control-Allow-Methods', '*');
res.setHeader("Access-Control-Allow-Headers", "*");
res.end();
});
// POST /login
app.post("/api/login", function(req, res) {
console.log(req.body)
});
app.listen(port, () => {
console.log("Server is on, baby")
})
login.js
import React, { Component } from 'react';
import axios from 'axios';
import './login.css';
class Login extends Component{
constructor(props) {
super(props)
this.state = {
email: "",
password: ""
}
}
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
}
handleSubmit = e => {
e.preventDefault();
const { email, password } = this.state;
const user = {
email,
password
};
axios
.post('http://localhost:5000/api/login', user)
.then(() => console.log('done'))
.catch(err => {
console.error(err);
});
};
render(){
return (
<div id="login">
<div className="background-inner-container">
{/* <p>{this.state.response}</p> --> */}
<div className="login-register-container padding-top padding-bottom padding-left padding-right">
<div className="login-register-title">Account Login</div>
<form onSubmit={this.handleSubmit}>
<input className="form-input" type="email" id="email" name="email" placeholder="Enter Email" onChange={this.onChange}/>
<input className="form-input" type="password" id="password" name="password" placeholder="Enter Password" onChange={this.onChange}/>
<button className="form-button" type="submit">Login</button>
</form>
</div>
</div>
</div>
);
}
}
export default Login
The problem is the Express middleware. An Express middleware takes three parameters: (req, res, next). Currently you are omitting the third parameter next, which is needed to forward the request to the following handlers. Also you are currently ending the response with res.end() before the POST handler function is reached.
Try this:
app.use('/api/login', function (req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader('Access-Control-Allow-Methods', '*');
res.setHeader("Access-Control-Allow-Headers", "*");
next();
});
I've removed the res.end() and called the next() function instead in order to proceed with the request.
EDIT
By the way, if you only want to set CORS header, there's a handy and very common Express middleware called cors, which is highly customizable and will fit your needs. You can use it like this:
const cors = require('cors')
// ...
app.use(cors())

Resources