How to pass users' data from nodeJS to reactJS using Express/Mysql - node.js

I need to pass author's email in my posts. I though I can do it by joining tables in my posts route, but it doesn't really work.
Here is my route :
router.get("/posts", async (req, res) => {
const { id } = req.session.user;
//const usersPosts = await user.$relatedQuery("posts");
try {
const user = await User.query().findById(id);
if (!user) {
return res.status(401).send("User was not found");
}
const posts = await Post.query()
.select([
"users.email",
"images.name",
"posts.category",
"posts.title",
"posts.description",
"posts.created_at"
])
.join("images", { "posts.image_id": "images.id" });
.join("users", { "posts.user_email": "users.email" });
console.log("it worked");
return res.status(200).send({ posts: posts });
} catch (error) {
console.log(error);
return res.status(404).send({ response: "No posts found" });
}
});
Here is code with my axios fetching the route :
function Home(props) {
const [posts, setPosts] = useState([]);
const getPosts = async () => {
try {
let response = await axios.get("http://localhost:9090/posts", {
withCredentials: true
});
console.log(response.data.posts);
setPosts(response.data.posts);
} catch (error) {
console.log(error.data);
}
};
useEffect(() => {
getPosts();
}, []);
And this is how I tried to return it:
{posts.map((post, index) => {
return (
<>
Author:<br></br>
<small>{post.user_email}</small>
</p>
<p>
Category:<br></br>
<small>{post.category}</small>
</p>
<p>
Description:<br></br>
<small>{post.description}</small>
</p>
<p>
Created: <br></br>
<small>{post.created_at}</small>
Everything works except the fetching Author.

a typo its user_email not users_email
your sending email in the value assingned to user_email and in front end using users_email

Related

React use axios return Axios Error {message: 'Network Error'} and TypeError: Cannot read properties of undefined (reading 'path')

when I click submit button, then web and terminal will return error like me title
but i try postman is ok , so i think is my axios setting error,how can i fixed this error? I found many similar questions, but can't not help me
the other question is , my form tag action is "/addItems", but i sending request , i got this error CANNOT POST / addItems Post http://localhost:3000/addItems 404 (Not Found)
(axios setting )
post(id, title, description, price, avatar) {
let token;
if (localStorage.getItem("user")) {
token = JSON.parse(localStorage.getItem("user")).token;
} else {
token = "";
}
const formData = new FormData();
// formData.append("id", id);
// formData.append("title", title);
// formData.append("description", description);
// formData.append("price", price);
formData.append("avatar", avatar);
return axios.post(
API_URL + "/addItems",
{ formData },
{
headers: {
Authorization: token,
"Content-Type": "multipart/form-data"
}
}
);
}
(item.route)
itemRouter.post("/addItems", upload.single("avatar"), async (req, res) => {
let { id, title, description, price, avatar } = req.body;
if (req.user.isMember()) {
return res.status(400).send("Only admin can add new items");
}
console.log(req.file);
avatar = req.file.path;
const newItem = new Item({
id,
title,
description,
price,
avatar
});
try {
await newItem.save();
console.log(req.file);
res.status(200).send("New item has been saved.");
} catch (err) {
res.status(400).send("Error");
console.log(err);
}
});
(addItemsComponent)
const handleChangePost = () => {
if (currentUser.user.role !== "admin") {
window.alert("Member can't not post item!! ");
navigate("/");
} else {
ItemService.post(avatar)
.then(() => {
window.alert("Post successfully");
navigate("/");
})
.catch((error) => {
console.log(error);
console.log(error.response);
setErrorMessage(error.response.data);
});
}
};
return (
<div>
<form action="/addItems" method="post" enctype="multipart/form-data">
<input onChange={handleChangeAvatar} value={avatar} type="file" name="avatar" />
<button type="submit" onClick={handleChangePost}>
Submit
</button>
</form>
</div>
);
Try this
return axios.post(API_URL + "/addItems", formData,
{
headers: {
Authorization: token,
"Content-Type": "multipart/form-data"
}
}
);

How to create a comment and reply section with MERN STACK

I created a comment session on my entertainment website
It’s working on backend.
It’s working on the frontend also but it’s not displaying the content the user typed on the database
This is my frontend (Comment form) logic:
export default function AddComment({ busy}) {
const [content, setContent] = useState("");
const { movieId } = useParams();
const { updateNotification } = useNotification();
const handleOnChange = ({ target }) => {
setContent(target.value);
};
const handleSubmit = async (e) => {
e.preventDefault();
const { error, message } = await addComment(movieId);
if (error) return updateNotification("error", error);
updateNotification("success", message);
const newComment = {
content,
};
setContent(newComment);
setContent("");
};
return (
<div className='p-5'>
<br />
<p className='dark:text-white text-primary'>replies</p>
<hr className='w-64' />
{/* Comment Lists */}
{/* Root Comment Form */}
{/* Form */}
<form className='flex ' onSubmit={handleSubmit} busy={busy}>
<textarea
value={content}
onChange={handleOnChange}
type='text'
autoComplete='text'
className='w-full rounded-md p-2 dark:text-white text-primary outline-none bg-transparent resize-none border-b focus:border-blue-500'
placeholder='Add New comment'
/>
<br className='dark:text-white text-primary ' />
<button
type='submit'
className=' w-5 h-14 dark:text-white text-primary bg-blue-600 hover:bg-blue-400 focus:border-blue-900 rounded-md'
>
{busy ? <ImSpinner3 className='animate-spin' /> : "Add"}
</button>
</form>
</div>
);
}
Then the addComment is coming from this API:
import { catchError, getToken } from "../utils/helper";
import client from "./client";
export const addComment = async (movieId, newComment) => {
const token = getToken();
try {
const { data } = await client.post(
`/comments/comment/${movieId}`,
newComment,
{
headers: {
authorization: "Bearer " + token,
},
}
);
return data;
} catch (error) {
return catchError(error);
}
};
The backend is working:
exports.createComment = expressAsyncHandler(async (req, res) => {
const { movieId } = req.params;
const { content } = req.body;
const userId = req.user._id;
console.log(req.body);
// verify user before comment
if (!req.user.isVerified)
return sendError(res, "Please verify your email first!");
if (!isValidObjectId(movieId)) return sendError(res, "Invalid Movie!");
// create and update new comment
const newComment = new Comment({
user: userId,
parentMovie: movieId,
content,
});
// save new comment
await newComment.save();
res.json({ message: "New comment added!!", newComment });
});
I posted with Postman on backend it gave me this on the database:
_id
:
62dcfccd93444cef55611632
user
:
62bf20d65073a7c65f549078
parentMovie
:
62c2c425465804ff32cdd06c
content
:
"hello"
createdAt
:
2022-07-24T08:03:25.666+00:00
updatedAt
:
2022-07-24T08:03:25.666+00:00
__v
:
0
on the console:
The port is listening on port 8000
connected to db
{ content: 'hello' }
POST /api/comments/comment/62c2c425465804ff32cdd06c 200 447.534 ms - 260
I posted on the frontend it gave me this on the database, no content:
_id
:
62dcfd6993444cef55611635
user
:
62bf57e8a8f3e737b2af23d9
parentMovie
:
62cc1d426785cfe42f8737a8
createdAt
:
2022-07-24T08:06:01.458+00:00
updatedAt
:
2022-07-24T08:06:01.458+00:00
__v
:
0
on the console it shows an empty object:
{}
POST /api/comments/comment/62cc1d426785cfe42f8737a8 200 364.009 ms - 242
This is how I solved the problem
Hope this solution will help many
const handleSubmit = async (e) => {
e.preventDefault();
const { error, message } = await addComment(movieId, content); // call the content and movieId from backend
if (error) return updateNotification("error", error);
updateNotification("success", message);
// push and display the content on database
const newComment = {
content,
};
setContent(newComment);
setContent("");
};
Then the API should be like this
export const addComment = async (movieId, newComment) => {
const token = getToken();
// console.log(newComment);
const body = {
content: newComment,
};
try {
const { data } = await client.post(`/comments/comment/${movieId}`, body, {
headers: {
authorization: "Bearer " + token,
},
});
return data;
} catch (error) {
return catchError(error);
}
};

xhr.js:210 DELETE http://localhost:3000/posts/62575cb61cb27c6417732193 403 (Forbidden) / cannot delete document

I am using axios for the request of my own api, everything works correctly except the DELETE request, I looked for information about the error but I have not found the solution. when I send the request to the server I get this error: "xhr.js:210 DELETE http://localhost:3000/posts/62575cb61cb27c6417732193 403 (Forbidden)".
I put this line of code in Package.Json to avoid problems with CORS:
"proxy": "http://localhost:8080/api"
This would be my api, for the operation I pass the post id by url and the user id:
(I tried it in postman and it works without any problem)
router.delete("/:id", async (req, res) => {
try {
const post = await Post.findById(req.params.id);
if (post.userId === req.body.userId) {
await post.deleteOne();
res.status(200).json("the post has been deleted");
} else {
res.status(403).json("you can delete only your post");
}
} catch (err) {
res.status(500).json(err);
}
});
and this is where I consume my api:
const Post = ({ date, _id,userId, description }) => {
const handleDelete = async () => {
try {
await axios.delete('posts/' + _id, { userId: currentUser._id })
} catch (error) {
console.log(error)
}
}
return(
<div onClick={handleDelete }>
//component content
</div>
)
}
export default Post
I solved it, sending a data object to my api (inside that object I put the user id):
const handleDelete = async () => {
try {
await axios.delete('/posts/' + _id, {
data: {
userId: currentUser._id
}
}
)
} catch (error) {
console.log(error)
}
}

Is there a way to stop reactjs status page from showing

I am building an ecommerce with mern stack
When I make request from react to node and it fails it show the status code with error on the page.
is there a way to prevent this from happening
enter image description here
React code
export const createCategories = async(name, token) => {
return await axios.post(
`${process.env.REACT_APP_SERVER_APP_URL}/api/category`,
name,
{
headers: {
'x-header-token' : token
}
}
)
}
const handleSubmit = async(e) => {
e.preventDefault();
setLoading(true)
try{
createCategories(category, localStorage.getItem('token'))
.then(res => {
console.log(res)
setLoading(false)
setCompleted(true)
setCreateCategory(res.data)
});
}catch(err){
setError(true)
setErrorMsg({
"msg": err.response.data
})
}
}
nodejs code
try{
const {name} = req.body;
const category = await new Category({ name, slug: slugify(name)}).save();
res.json({'msg': "Category Created"})
}catch(err){
res.status(400).send("Create Category Failed...")
console.log(err)
}
you should use catch block
createCategories(name,token).then(res => {
// if success in response
}).catch(error => {
// if error in response
})

how to create poll using API with react functional component

this is my react js code and I want to connect with my node js API but I don't understand how to that ...!
import React, { useState } from "react";
import Poll from "react-polls";
// import "./styles.css";
/**
* https://stackoverflow.com/questions/65896319/react-js-class-poll-convert-into-react-hooks-poll
*/
// Declaring poll question and answers
const pollQuestion = "Youtube is the best place to learn ?";
const answers = [
{ option: "Yes", votes: 7 },
{ option: "No", votes: 2 },
{ option: "don't know", votes: 1 },
];
const Fakepolls = () => {
// Setting answers to state to reload the component with each vote
const [pollAnswers, setPollAnswers] = useState([...answers]);
// Handling user vote
// Increments the votes count of answer when the user votes
const handleVote = (voteAnswer) => {
setPollAnswers((pollAnswers) =>
pollAnswers.map((answer) =>
answer.option === voteAnswer
? {
...answer,
votes: answer.votes + 1,
}
: answer
)
);
};
return (
<div>
<Poll
noStorage
question={pollQuestion}
answers={pollAnswers}
onVote={handleVote}
/>
</div>
);
};
export default function App() {
return (
<div className="App">
<Fakepolls />
</div>
);
}
It work's fine with
// Declaring poll question and answers
const pollQuestion = "Youtube is the best place to learn ?";
const answers = [
{ option: "Yes", votes: 7 },
{ option: "No", votes: 2 },
{ option: "don't know", votes: 1 },
];
but I want to connect this poll with my API instead of Declaring it ..! this is my api- to get data -> ( router.get("/poll/:pollId", getPoll); //)
exports.getPoll = async (req, res, next) => {
try {
const { pollId } = req.params;
const polls = await Poll.findById(pollId);
if (!polls) throw new Error("no polls found");
res.status(200).json(polls);
} catch (error) {
error.status = 400;
next(error);
}
};
This is a postman image -
and this API for POST data- and my node js code -
exports.votes = async (req, res, next) => {
try {
/**
* 1. get the poll from db
* 2. check if the user already exists in any option
* 3. if user has already selected any option do nothing
* 4. if user has selected any other option remove from that option
* 5. if user does not exist in any option, insert his user id to selected option
*/
const { pollId } = req.params;
let { userId, answer } = req.body;
// get selected poll from db
const poll = await Poll.findById(pollId);
if (answer && poll) {
answer = answer.toLowerCase();
///Finf the Poll
let existingVote = null;
Object.keys(poll.options).forEach((option) => {
// loop on all options, check if the user already exists in any option
if (poll.options[option].includes(userId)) {
existingVote = option;
}
});
if (existingVote == null) {
// if there is no existing vote save it to db
try {
const push = {};
push[`options.${answer}`] = userId;
const update = await Poll.findByIdAndUpdate(
pollId,
{ $push: push },
{ upsert: true }
);
res.status(201).json(update);
} catch (err) {
error.status = 400;
next(error);
}
} else if (existingVote && existingVote.length > 0) {
// check if answer is same as previous, if yes send not modified
if (existingVote.toLowerCase() === answer.toLowerCase()) {
res.status(304).send("Response already saved");
} else {
// delete the previous response and save it in new
if (
Array.isArray(poll.options[existingVote]) &&
poll.options[existingVote].length > 0
) {
// TODO: filtering this is not returning array but 1
poll.options[existingVote] = poll.options[existingVote].filter(
(vote) => vote != userId
);
poll.options[answer] = poll.options[answer].push(userId);
const update = await Poll.findByIdAndUpdate(pollId, {
$set: { options: poll.options },
});
res.status(201).json(update);
}
}
} else {
error = {
status: 500,
message: "Something went wrong",
};
next(error);
}
} else {
error = {
status: 404,
message: "Poll not found",
};
next(error);
}
} catch (error) {
error.status = 400;
next(error);
}
};
this is a POSTMAN image using POST to store data --- >
how can I connect API with react poll
What you'd do is make a fetch() to your /api/polls endpoint inside your Fakepolls component, the URL being exactly as you show in your Postman screenshot. More info on fetch here at the MDN docs.
With the response you get from the endpoint, populate the answers array you component uses. From what I see, it would require a bit of transformation as your answer object is not quite the same as what Poll needs.
Next, upon user action, as well as updating the votes in the UI, you need to make another fetch to your vote endpoint.
Here's your component again with these adjustments. Keep in mind it's untested and the URLs are obviously not real:
import React, { useState, useEffect } from "react";
import Poll from "react-polls";
// import "./styles.css";
/**
* https://stackoverflow.com/questions/65896319/react-js-class-poll-convert-into-react-hooks-poll
*/
const Fakepolls = () => {
// Setting answers to state to reload the component with each vote
const [pollQuestion, setPollQuestion] = useState('');
const [pollAnswers, setPollAnswers] = useState([]);
// Query the actual poll info from the server
useEffect(() => {
fetch('http://your-server/api/polls/you-poll-id')
.then((response) => response.json()) //parse response as json
.then((pollObject) => {
let answerCountDictionary = Object.keys(pollObject.options)
.map(oKey => {
return {
option: oKey,
anwers: pollObject.options[oKey].length
}
}); //iterate over the 'options' properties' keys to get the names and the current votes
setPollAnswers(answerCountDictionary);
setPollQuestion(pollObject.question)
})
.catch((error) => {
console.error('Error:', error);
});
},[]) //adding empty array of dependencies to prevent multiple calls on state change
// Handling user vote
// Increments the votes count of answer when the user votes
const handleVote = (voteAnswer) => {
setPollAnswers((pollAnswers) =>
pollAnswers.map((answer) =>
answer.option === voteAnswer
? {
...answer,
votes: answer.votes + 1,
}
: answer
)
);
//also submit the backend
fetch('http://your-server/api/vote/poll-id', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: {
"userId": "the-logged-in-user",
"answer": voteAnswer
},
})
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
};
return (
<div>
<Poll
noStorage
question={pollQuestion}
answers={pollAnswers}
onVote={handleVote}
/>
</div>
);
};
export default function App() {
return (
<div className="App">
<Fakepolls />
</div>
);
}

Resources