Deleting items in mongodb using reactjs doesn't work - reactjs

I'm using reactjs as frontend and expressjs as backend.
the server got hacked with a low power ransomware but didn't affect the website files themselves but i had to add firewall on mongod instances to limit the other IPs to access the database and it all worked out great, after that i tried to add an item in the database using the frontend and it worked alright reading the data works and adding data works the problem was with the deleting when i delete using postman the request is sent and deletes the item ok, and when using firefox dev tools i edited my request to delete the specific item and it deleted it but when using frontend it doesn't do anything no request is sent doesn't give me any response no status codes no nothing.
The Frontend:
class AdminCardComp extends Component {
constructor(props) {
super(props);
this.state = {
appartmentId: ''
};
this.onChange = this.onChange.bind(this);
this.handleRemove = this.handleRemove.bind(this);
}
onChange(e) {
if (e.target.id === 'appartmentId') {
this.setState({ appartmentId: e.target.value });
}
}
handleRemove(){
this.props.delAppartment(this.state.appartmentId);
/*axios.delete("http://172.105.245.241:3443/appartments/"+this.state.ID,{ params: { appartmendId: this.state.ID }} , {}).then(res => {
console.log(res.data)
})*/
}
render() {
const appartmentRender = this.props.appartments.appartments.map((appartment) => {
var x = 1;
return(
<Card>
<CardImg top src={baseUrl + appartment.image[0].image} alt={appartment.name} />
<CardBody>
<CardTitle>Appartment Number: {x}</CardTitle>
<CardText>Appartment Description: {appartment.description}</CardText>
<CardText>Appartment Price: {appartment.price}</CardText>
</CardBody>
<CardFooter>
<CardText>App ID: {appartment._id}</CardText>
</CardFooter>
</Card>
);
x++;
})
return (
<>
<div className="container col-12">
<div className="row row-content col-12 col-sm-6">
{appartmentRender}
</div>
<div className="row row-content col-12 col-sm-6 justify-content-center">
<Form onSubmit={this.handleRemove}>
<Row>
<Col>
<Input className="formBack" onChange={this.onChange} type="text" id="appartmentId" name="appartmentId" placeholder="Enter ID" innerRef={(input) => this.appartmentId = input} />
</Col>
</Row>
<Row>
<Col>
<Button className="offset-sm-3 col-sm-5 buttonmr formBackButton" type="submit" value="submit">Remove</Button>
</Col>
</Row>
</Form>
</div>
</div>
</>
);
}
}
the delAppart method is in the ActionCreators file
export const delAppartment = (appartmentId) => (dispatch) => {
const bearer = 'Bearer' + localStorage.getItem('token');
return fetch(baseUrl + 'appartments/' + appartmentId ,{
method: "DELETE",
body: JSON.stringify({ "_id": appartmentId }),
headers: {
"Content-Type": "application/json"
},
credentials: "same-origin"
})
.then(response => {
if(response.ok){
return response;
}else {
var error = new Error('Error ' + response.status + ': ' + response.statusText);
error.response = response;
throw error;
}
},error => {
throw error;
})
}
given that everything worked before the attack, and as you see in the frontend i tried using axios and nothing has changed
The Backend
appartRouter.route('/:appartmentId')
.options((req,res) => {
res.sendStatus(200);
})
.get((req,res,next) =>{
Appartments.findById(req.params.appartmentId)
.then((appartment) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(appartment);
}, (err) => next(err))
.catch((err) => next(err));
})
.delete((req,res,next) =>{
Appartments.findByIdAndRemove(req.params.appartmentId)
.then((resp) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(resp);
}, (err) => next(err))
.catch((err) => next(err));
})
This is the networks tab when trying to remove an item i suspect the first one says it's a GET type and it should've been DELETE type i'm not sure

It seems to be a problem with CORS. I would recommend to read more about it here.
Also it would be helpful to have a screenshot or more info about the network request in the Network tab in Chrome Dev Tools.

Related

MongoDB + React - Obtain a document from db based on a query I am passing

I am trying to access a document from my MongoDB Atlas db that contains a specific key, based on a query I am passing in the fetch. I've followed the guides on the backend setup from MongoDB, it's all working, I'm connected to it, and now here's what I'm trying to do:
Documents look like this:
{
invitationCode: string;
name: string;
numberOfPeople: number;
specialMentions: string;
confirmed: boolean;
}
In the frontend, there's only one input at first, where the user should be entering his invitation Code. Once he clicks on the button, a request should be made to the BE, sending the value he entered. The BE should look through the documents and find the document that contains the invitationCode mathing with the input (The invitation codes are all unique). After the BE identified the document, it should be sent back to the frontend, so I can juggle with it here (display the name of the person, show the other 3 fields, etc.)
Here's what I have so far:
in my record.js file (backend):
const express = require("express");
const recordRoutes = express.Router();
const dbo = require("../db/conn");
const ObjectId = require("mongodb").ObjectId;
recordRoutes.route('/record/invitations').post(function (req, res) {
let db_connect = dbo.getDb();
let myquery = req.body.invitationNumber;
console.log('MYQUERY:', myquery);
db_connect
.collection('records')
.findOne({zzceva: myquery}, function (err, result) {
if (err) throw err;
console.log('RESULT FROM BE', result);
res.send(result);
})
console.log('QUERY:', myquery);
})
and in the frontend I have this logic:
const onSubmit = useCallback(async (e) => {
e.preventDefault();
if (personEnteredCode) {
const newPerson = { ...form };
await fetch("http://localhost:5000/record/add", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newPerson),
})
.catch(error => {
window.alert(error);
return;
});
setForm({ invitationNumber: "", numberOfPeople: "", specialMentions: "" });
navigate("/");
console.log('newPerson:', newPerson);
} else {
// THIS IS WHAT DOES NOT WORK >>>>>>>>>>>>>>>>>>>>>>>>>>>
// I AM TRYING TO SEND THE invCode back to the BE
const invCode = form.invitationNumber;
await fetch("http://localhost:5000/record/invitations", {
method: 'POST',
body: JSON.stringify(invCode),
})
.then((response) => {
console.log('THE RESPONSE IS:', response);
setCurrentPerson(response);
})
.catch(error => {
window.alert(error);
return;
})
.finally(() => setPersonEnteredCode(true))
}
// When a post request is sent to the create url, we'll add a new record to the database.
}, [form, navigate, personEnteredCode])
return (
<div className="confirm-form">
<form onSubmit={onSubmit}>
<div className="form-group">
<label htmlFor="invitationCode">Cod invitație:</label>
<input
type="text"
className="form-control"
id="invitationCode"
value={form.invitationNumber}
onChange={(e) => updateForm({ invitationNumber: e.target.value })}
/>
</div>
{!personEnteredCode && <input type={'submit'} value={'OK'}/>}
{personEnteredCode && <div className="form-group">
<label htmlFor="numberOfPeople">Număr persoane:</label>
<input
type="number"
className="form-control"
id="numberOfPeople"
value={form.numberOfPeople}
onChange={(e) => updateForm({ numberOfPeople: e.target.value })}
/>
</div>}
{personEnteredCode && <div className="form-group">
<div className="form-check form-check-inline">
<label htmlFor="specialMentions">Mențiuni speciale:</label>
<input
type="text"
className="form-control"
id="specialMentions"
value={form.specialMentions}
onChange={(e) => updateForm({ specialMentions: e.target.value })}
/>
</div>
</div>}
{personEnteredCode &&<div className="form-group">
<input
type="submit"
value="Confirmă"
className="btn btn-primary"
/>
</div>}
</form>
</div>
);
}
After many different tries, now the response I'm getting is 200 (not 404 not found or 500 like the first tries), but on the response object, I don't see the information I need, instead this is how a console.log looks like:
HUGE thanks in advance for any kind of guidance or help you could provide. I'm trying to understand what I'm doing wrong.
The issue is that you're logging the fetch response and not the data in the response body (so congrats! you're getting a response!).
The fetch response has a couple of different methods that you can use to read the data in the body. Depending on the type of data your API is returning, you'll use the appropriate method (.json, .text, .blob, etc.). These methods return a promise meaning they are asynchronous. Here's how you might modify your code:
fetch("http://localhost:5000/record/invitations", {
method: 'POST',
body: JSON.stringify(invCode)
})
.then((response) => {
return response.json()
})
.then((data) => {
//now you've got the data to put in state
setCurrentPerson(response);
})
.catch(error => {
window.alert(error);
return;
})
}
I can see that in your Express route, you're using res.send(result). You'll probably want to change that to: res.json(result). Both behave the same if you pass an object or array, but res.json() will explicitly convert your results to JSON.
Also, you didn't ask about it, but generally, you wouldn't use POST for this route. In REST, this would be a GET route and you'd generally pass the data as a param or querystring to your API.

PUT Request - Uploading a file - React / Express / Multer - req.file = undefined

I'm developping a social network for a school project, and I want to allow the user to update his/her information, specifically the profile Photo and the cover Photo.
I use multer for storing images.
When I try to upload an image using a POST request, it works perfectly fine but on a PUT request it says req.file /req.files is always undefined.
// FORM (IMPORTANT PART)
<form
className="update__form"
onSubmit={handleSubmit}
encType="multipart/form-data"
id="form"
>
{/* GESTION PHOTO DE COUVERTURE */}
<div className="update__form-cover">
<input
type="file"
name="coverPhotoUrl"
className="update__form-cover-input"
id="cover"
accept="image/*"
onChange={handleCover}
/>
<div className="update__form-cover-button">
Modifier la photo de couverture
</div>
</div>
<div
className={
loadCover === true
? 'update__form-cover-img'
: 'update__form-cover-img--close'
}
>
<img id="coverImg" alt="ok" />
</div>
{/* GESTION PHOTO DE PROFIL */}
<div className="update__form-profile">
<input
type="file"
name="profilePhotoUrl"
className="update__form-profile-input"
id="profile"
accept="image/*"
onChange={handleProfile}
/>
<div className="update__form-profile-button">
Modifier la photo de profil
</div>
</div>
<div
// MY DIFFERENTS FUNCTIONS
// TO DISPLAY AND STORE THE NEW COVER (USESTATE)
const handleCover = () => {
const coverChange = document.getElementById('cover').files
if (coverChange.length > 0) {
const fileReader = new FileReader()
fileReader.onload = function (event) {
document
.getElementById('coverImg')
.setAttribute('src', event.target.result)
setLoadCover(true)
setData({
...data,
coverPhotoUrl: coverChange[0],
})
}
fileReader.readAsDataURL(coverChange[0])
}
}
// DISPLAY AND STORE THE NEW PROFILE PHOTO (USESTATE)
const handleProfile = () => {
const profileChange = document.getElementById('profile').files
setData({
...data,
profilePhotoUrl: profileChange[0].name,
})
if (profileChange.length > 0) {
const test = new FileReader()
test.onload = function (event) {
document
.getElementById('profileImg')
.setAttribute('src', event.target.result)
setLoadProfile(true)
}
test.readAsDataURL(profileChange[0])
}
}
// FUNCTION CALLED WHEN FORM IS SUBMITTED
const handleSubmit = (event) => {
event.preventDefault()
try {
updateUser(data)
} catch (err) {
console.log(err)
}
}
// FUNCTION TO FETCH PUT
const updateUser = (data) => {
console.log(data)
const userId = localStorage.getItem('userId')
fetch('http://localhost:8000/api/user/' + userId, {
method: 'PUT',
headers: {
'Content-Type': 'form-data',
},
body: JSON.stringify(data),
})
}
export default updateUser
// BACK CONFIG
const multer = require('multer');
const MIME_TYPES = {
'image/jpg': 'jpg',
'image/jpeg': 'jpeg',
'image/png': 'png',
'image/svg': 'svg',
}
const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, '../images')
},
filename: (req, file, callback) => {
const name = file.originalname.split(' ').join('_');
const extension = MIME_TYPES[file.mimetype];
callback(null, name + Date.now() + '.' + extension);
}
});
const upload = multer({ storage: storage });
router.put('/:id', upload.array(), userCtrl.updateUser);
// CONTROLLER (not very important HERE BUT RETURN REQ.FILE UNDEFINED)
exports.updateUser = ((req, res, next) => {
console.log(req.file)
console.log(req.files)
const userInfos = req.file ? {
...JSON.parse(req.body.data),
coverPhotoUrl: `${req.protocol}://${req.get('host')}/images/${req.file.filename}`
} : {
...req.body
};
delete userInfos._userId;
User.findOne({
_id: req.params.id
})
.then((user)=> {
User.updateOne({
_id: req.params.id
},
{
...userInfos,
_id: req.params.id
})
.then(()=> res.status(200).json({ message : 'infos mises à jour ! '}))
.catch((error)=> res.status((401)).json({ error }));
})
.catch((error)=> res.status(400).json({ error }));
});
If someone come on this, i've finally found the answer :
first : use the formData constrcutor form-data-infos mdn, to put your datas in (formdata.append())
second : on the function who will fetch (front to back) : just remove the 'content-type', the browser will automatically set this,
it should run normally then
I also want to apologize for this 'useless' post because all the answers were on this forum (and on the web), my eyes were just closed

Is this an efficient way to send data between components using Link from react router?

I want to know if the way I implemented the transfer of data between two components, is the efficient way. To be more precise, in one component that is called TableComponent.js I am fetching data from an API and then with Link from react router, I am sending that data to another component called User.js.
User.js component is used for editing or creating new users based on the fact if an url has an ID passed with Link. If the Link is not sending an ID then the path will be: /users/new, but if it has an ID then the path will be: /users/ID (id of the clicked user in the table)
Let me show you the code.
I am going to show you just a part where I am sending data with Link in TableComponent.js, as other part is not necessary and the code is quite big:
<Link
to={{
pathname: `/users/${apiData.id}`,
user: {
name: apiData.name,
email: apiData.email,
status: apiData.status,
gender: apiData.gender,
},
}}
>
{apiData.name}
</Link>
This is now the User.js component:
const User = (props) => {
const { name, email, status, gender } = props.location.user;
const { id } = useParams();
const [newName, setNewName] = useState(name);
const [newEmail, setNewEmail] = useState(email);
const [newStatus, setNewStatus] = useState(status);
const [newGender, setNewGender] = useState(gender);
const updateName = (e) => {
setNewName(e.target.value);
};
const updateEmail = (e) => {
setNewEmail(e.target.value);
};
const updateStatus = (e) => {
setNewStatus(e.target.value);
};
const updateGender = (e) => {
setNewGender(e.target.value);
};
const updateData = () => {
if (id) {
axios
.put(
`${process.env.REACT_APP_API_URL}users/${id}`,
{
name: newName,
email: newEmail,
status: newStatus,
gender: newGender,
},
{
headers: {
Authorization: `Bearer ${process.env.REACT_APP_API_TOKEN}`,
},
}
)
.catch(function (error) {
if (error.response.status === 422) {
alert(
"Error: The format of email is wrong! Please put it like this: yourname#yourname.com"
);
}
});
} else {
axios
.post(
`${process.env.REACT_APP_API_URL}users/`,
{
name: newName,
email: newEmail,
status: newStatus,
gender: newGender,
},
{
headers: {
Authorization: `Bearer ${process.env.REACT_APP_API_TOKEN}`,
},
}
)
.catch(function (error) {
if (error.response.status === 422) {
alert("Error: Name or email already taken!");
}
});
}
};
return (
<Layout title={id ? "Edit User" : "Create User"} hasSearchBox={false}>
<ActionsInputsContainer data-testid="actionspage-inputs">
<NameInputContainer>
<ActionsInputs
labelName="Name:"
placeholder="Insert the name..."
value={newName}
onChange={updateName}
/>
</NameInputContainer>
<EmailInputContainer>
<ActionsInputs
labelName="Email:"
placeholder="Insert the email..."
value={newEmail}
onChange={updateEmail}
/>
</EmailInputContainer>
<SelectInput value={newStatus} onChange={updateStatus}>
<MenuItem value="active">Active</MenuItem>
<MenuItem value="inactive">Inactive</MenuItem>
</SelectInput>
<SelectInput value={newGender} onChange={updateGender}>
<MenuItem value="male">Male</MenuItem>
<MenuItem value="female">Female</MenuItem>
</SelectInput>
<ButtonsContainer data-testid="actionspage-buttons">
<Link to="/users">
<CancelButton variant="outlined" text="CANCEL"></CancelButton>
</Link>
<Link to="/users">
<ActionsButton
onClick={updateData}
variant="filled"
text="ACCEPT"
data-testid="actionspage-updatebutton"
></ActionsButton>
</Link>
</ButtonsContainer>
</ActionsInputsContainer>
</Layout>
);
};
As you can see in this component I am sending the ID like a parameter whereas other data is being send using props. Is this a good way, because now I have certain bugs for example, if I refresh the page it fails, because there are no props being send. Also is it a good practice to send certain data as url parameter and other via props. If you could help me to make this code more efficient, I would be thankful.

Why is my firebase chat showing messages only if I exit the screen or close the chat and re-open it?

The chat is supposed to be instant where messages populate the div as they are entered and stored in Firebase Firestore. However, I noticed a strange thing. The Chat shows a new message only when I change tabs in Chrome or when I close the chat completely and then re-open it. Otherwise, if I stay on the same tab looking at the Chat and waiting for the new message to show, it does not show up. Really strange.
JSX:
<div className="form-popup" id="myForm">
<form className="form-container" onSubmit={this.chatFormSubmit}>
<h1>Chat</h1>
<label htmlFor="msg"><b>Message</b></label>
<div className="chatArea" id='messages'>
{this.state.messages.map((message, index) => {
return <p key={index}>{message.body.content}</p>
})}
<div style={{ float:"left", clear: "both" }}
ref={(el) => { this.myRef = el; }}>
</div>
</div>
<textarea className="chatInput" ref={this.chatArea} ></textarea>
<br />
<br />
{this.state.writeError ? <p>{this.state.writeError}</p> : null}
<button type="submit" className="btn">Send</button>
<button type="button" className="btn cancel" onClick={() => this.closeForm()}>Close</button>
</form>
</div>
REACTJS:
This is the function that opens the Chat and starts the onSnapshot function to listen to changes in Firestore:
startChatWithProjectManager(doc) {
document.getElementById("myForm").style.display = "block";
this.setState({docId: doc.id})
const query = firebase.firestore()
.collection('Clients')
.doc(this.state.displayName)
.collection('Orders')
.doc(doc.id)
.collection('Messages')
.where("uid", "==", this.state.uid)
.orderBy('timestamp', 'desc')
.limit(12);
// Start listening to the query.
this.unsubFromMessages = query.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === 'removed') {
console.log(change.id)
} else {
this.setState(state => {
const messages = [...state.messages, {id: change.doc.id, body: change.doc.data()}]
return {
messages
}
}, this.scrollToBottom() )
}
});
});
}
This is the function that stores new messages in Firestore:
chatFormSubmit(e) {
e.preventDefault();
this.setState({ writeError: null });
firebase.firestore()
.collection('Clients')
.doc(this.state.displayName)
.collection('Orders')
.doc(this.state.docId)
.collection('Messages')
.doc()
.set({
content: this.chatArea.current.value,
timestamp: moment().format('MMMM Do YYYY, h:mm:ss a'),
uid: this.state.uid,
name: this.state.displayName,
email: this.state.email
})
.catch((error) => {
this.setState({ writeError: error.message });
})
.then(this.chatArea.current.value = '')
}
For some reason, the messages appear in the ChatArea div very slowly with a weird delay unlike the examples that I followed from the Web where messages pop up almost instantly. I can not figure out what is going on.
I figured it out. The reason the chat was not updating as it was supposed to be was that one of the setInterval functions that I had was running concurrently and continuously, thus slowing down my app. Anyone out there puzzled why their code would not work when everything seems right, always check to see if there are any other functions that are causing infinite loops or other issues. Infinite loops interfere with network requests.

Meteor - callback executing twice

I have this Meteor app that sends data to an api then uses the data sent back in the website. However, when I call the function that gets the api data, uploadToCloudinary() which has a callback, I find it running twice. One of the documents get inserted correctly with the correct information and one is missing the res.data.secure_url. Am I not doing the callback thing right or is it because it is non-blocking code, so I think(correct me if I am wrong) that when the imageURL.push function executes, it cannot find a res so it goes and does the other code first and then when it finds the res it pushes it and creates another document.
import { Meteor } from "meteor/meteor"
import React from "react";
import { withRouter, Link } from "react-router-dom";
import SimpleSchema from "simpl-schema";
import axios from "axios"
import { SubjectRoutes } from "./subjectRoutes/subjectRoutes";
import "../methods/methods";
import Menu from "./subComponents/Menu";
class AddNote extends React.Component{
constructor(props){
super(props);
this.state = {
message: "",
loginMessage: (<div></div>),
urls: []
};
}
renderSubjects(subjects){
return subjects.map((item) => {
return <option key={item}>{item}</option>
})
}
componentWillMount() {
Meteor.subscribe('user');
}
addNote(e){
e.preventDefault();
let title = this.refs.title.value;
let subject = this.refs.subject.value;
let description = this.refs.description.value;
let allUrls = [this.refs.imageURL.value].concat(this.state.urls);
let imageURL = allUrls.filter(function(entry) { return entry.trim() != ''; });
let userId = Meteor.userId();
let userEmail = Meteor.user().emails[0].address;
let createdAt = Date.parse(new Date());
let unit = this.refs.unit.value;
let file = this.refs.fileInput.files[0];
if(!Meteor.userId()){
this.setState({
message: "You need to login before you can add a note",
loginMessage: <Link to="/login">Login</Link>
})
throw new Meteor.Error(400, "User is not signed in.")
}
if(title && subject && description && unit){
if(imageURL.length == 0 && file == undefined){
this.setState({ message: "You need to enter an image." })
return;
}
console.log(imageURL.length, file)
if(imageURL){
let noteInfo = { title, subject, description, imageURL, userId, userEmail, createdAt, unit };
Meteor.call("notes.insert", noteInfo, (err, res) => {
if(err){
this.setState({ message: "Please enter a valid image URL." });
}else{
this.props.history.push("/")
}
})
}
if(file){
let noteInfo = { title, subject, description, imageURL, userId, userEmail, createdAt, unit };
this.uploadToCloudinary(file, (err, res) => {
imageURL.push(res.data.secure_url);
Meteor.call("notes.insert", noteInfo, (err, res) => {
//problem .......inserting 2 docs, one empty and one with proper data
console.log("CALLED")
if(err){
this.setState({message: err.reason});
console.log(err);
}else{
this.props.history.push("/")
}
})
});
}
}
}
addLink(){
let file = this.refs.fileInput.files[0];
if(this.refs.imageURL.value || file != undefined){
if(this.state.urls.length < 10){
if(!this.state.urls.includes(this.refs.imageURL.value)){
const URLSchema = new SimpleSchema({
imageURL:{
type:String,
label:"Your image URL",
regEx: SimpleSchema.RegEx.Url
}
}).validate({ imageURL:this.refs.imageURL.value })
let urls = this.state.urls.concat([this.refs.imageURL.value]);
this.setState({ urls });
this.refs.imageURL.value == "";
}else{
this.setState({ message: "You already inserted this note." })
}
}else{
this.setState({ message: "Only allowed 10 notes per upload. "})
}
}else{
this.setState({ message: "Please enter a note." })
}
}
uploadToCloudinary(file, callback){
const CLOUDINARY_URL = "MY_CLOUDINARY_URL";
const CLOUDIARY_UPLOAD_PRESET = "MY_CLOUDIARY_UPLOAD_PRESET"
let formData = new FormData();
formData.append("file", file);
formData.append("upload_preset", CLOUDIARY_UPLOAD_PRESET)
axios({
url: CLOUDINARY_URL,
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
data: formData
}).then(function(res){
callback(new Meteor.Error(400, "Error, cannot connect to cloudinary."), res);
}).catch(function(err){
console.log(err);
})
console.log(file);
}
render(){
return(
<div>
<form onSubmit={this.addNote.bind(this)}>
<Menu />
<p>*Just a friendly reminder: If you cannot read the note yourself,
others cannot as well. Please make sure your notes are clear and
easy to read.*</p>
<h1>Add a note</h1>
<br />
<input className="addNote-input" id="title" ref="title" type="text" placeholder="Title" autoComplete="off" />
<br />
<select ref="subject">
<option selected disabled value="">Choose a subject</option>
{this.renderSubjects(SubjectRoutes)}
</select>
<br />
<input className="addNote-input" id="description" ref="description" placeholder="Description Here..." autoComplete="off" />
<br />
<Link to="/questions">What is this?</Link><br />
<div className="inline full">
<div className="left">
<input id="imageUrl" className="addNote-input insert-link" ref="imageURL" placeholder="Enter image URL here" autoComplete="off" />
</div>
or
<div className="right">
<input className="addNote-input inline" type="file" ref="fileInput" onChange={this.readImage} id="fileInput" autoComplete="off"/>
</div>
<div className="full inline-block">
<span onClick={this.addLink.bind(this)} id="addLink">+</span>
<span>({this.state.urls.length})</span>
</div>
</div>
<input className="addNote-input" placeholder="Subject Unit" type="text" ref="unit" autocomplete="off" />
<br />
<button>Add Note</button>
<br />
<div className="alert alert-danger">Error: {this.state.message}</div>
<br />
{this.state.loginMessage}
</form>
</div>
)
}
}
export default withRouter(AddNote);
PS the function uploadToCloudinary() just receives data as an argument and sends it to an api then puts it into a callback to return an object. And also the console.log("CALLED") is only executed once which is really confusing to me since it is creating two documents so it should be running twice. Thanks in advance!
You're calling notes.insert method twice in addNote():
In if (imageURL) { ... }
In if (file) { ... } — this one is calling uploadToCloudinary first and adds secure_url into imageURL.

Resources