I'm using a react and nodejs as backend, backend work properly I guess when I tried in postman but when trying to connect into my frontend it didnt insert the properly
here's the code in react app
class CreateChapter extends React.Component {
constructor(props){
super(props);
this.state={
// editorState: EditorState.createWithContent(convertFromRaw(JSON.parse(content))),
titleChapter: "",
editorState: EditorState.createEmpty(),
id: this.props.location.state.id,
status: '',
errorSaving: '',
saved: false
}
}
// handle editor change
onEditorStateChange = (editorState) => {
this.setState({ editorState })
}
//handle title change
onTitleChange = (event) => {
this.setState({
titleChapter: event.target.value
})
}
//load data chapter saved
loadChapterSaved = (data) => {
this.setState({
titleChapter: data.titleChapter,
editorState: data.editorState,
status: 'saved'
})
}
//load data chapter published
loadChapterPublished = (data) => {
this.setState({
titleChapter: data.titleChapter,
editorState: data.editorState,
status: 'published'
})
}
//save data
onSaveData = () => {
const convertedData = convertToRaw(this.state.editorState.getCurrentContent());
fetch('http://localhost:3001/new-chapter',{
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
id: this.state.id,
editorState: convertedData,
titleChapter: this.state.titleChapter,
status: this.state.status
})
})
.then(response => response.json())
.then( chapter => {
console.log(chapter)
if(chapter === 'empty input'){
this.setState({
errorSaving: 'Please fill Title Chapter and the Content'
})
}else{
this.loadChapterSaved(chapter);
}
})
}
render() {
const { classes, ...rest } = this.props;
const {editorState, id, errorSaving, saved} = this.state;
console.log('status', this.state.status)
return (
<div>
<HeaderHome/>
<div className={classNames(classes.main, classes.mainRaised)}>
<div className={classes.container}>
<div className={classes.storymargin}>
<h2 className={classes.title}>New Chapter</h2>
<Card className={classes.chaptercontainer}>
<CardContent>
<TextField
fullWidth
label=" New Chapter Title"
id="chapter-title"
onChange={this.onTitleChange}
InputProps={{
disableUnderline: true,
classes:{
input: classes.titleinput
}
}}
InputLabelProps={{
shrink: true,
className: classes.titleformlabel
}}
margin="normal"
/>
<Editor
editorState={editorState}
wrapperClassName={classes.homewrapper}
editorClassName={classes.homeeditor}
toolbarClassName={classes.toolbar}
placeholder="Begin typing..."
onEditorStateChange={this.onEditorStateChange}
/>
</CardContent>
{errorSaving ?
<div className={classes.errorSavingChap}>
{errorSaving}
</div>
:
""
}
<CardActions className={classes.displaybutton}>
<Button size="small" clor="primary" className={classes.buttonnextchap}
onClick={this.onSaveData}>
Save
</Button>
<Button size="small" clor="primary" className={classes.buttonnextchap}
onClick={this.onPublishData}>
Publish
</Button>
</CardActions>
</Card>
</div>
</div>
</div>
<div className={classes.footer}>
<Footer />
</div>
</div>
);
} }
export default withStyles(createStoryStyle)(CreateChapter);
the problem is this.state.status didnt send to the backend properly, it always receives initial state which is null. I think it has something to do with how setState is asynchronous, but I'm not quite sure. When I tried it in postman, it does work.
here's my backend
app.post('/new-chapter', (req, res) => {
const { id, titleChapter, editorState, status } = req.body;
if(titleChapter === '' || editorState === ''){
db('story').where('id_user', '=', id)
.increment('chapter', 0)
.returning('chapter')
.then( chapter => {
res.json('empty input')
})
.catch( err => res.json('cannot add chapter'))
}else{
db('story').where('id_user', '=', id)
.increment('chapter', 1)
.returning('chapter')
.then( chapter => {
db.select('entry').from('story').where('id_user', '=',id)
.then( newChap => {
const chapterEntry = newChap[newChap.length - 1].entry;
db('chapter').where('id_user', '=', id)
.returning('*')
.insert({
chapter: chapter[0],
titlechapter: titleChapter,
content: editorState,
id_user: id,
status: status,
entry: chapterEntry,
})
.then( newChapter => {
res.json(newChapter[0])
})
.catch( err => res.json('cannot add new chapter'))
}
)
})
.catch( err => res.json('cannot add new chapter'))
}
})
Related
Server
The server prints the groups
I am Trying to retrieve all groups from my Mongodb database but the value keeps returning as undefined.
I am creating a react app but i might be getting confused with Aync and how to use the promise
router.get('/groups', async (req, res) => {
try {
const groups = await Group.find().sort({ date: -1 });
res.json(groups);
console.log(groups);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
Actions
i cant also see the groups being printed here
export const getAllGroups = () => async (dispatch) => {
axios
.get("/api/group/groups")
.then(res =>
dispatch({
type: GET_GROUPS,
payload: res.payload.data
})
)
.catch(err =>
dispatch({
type: GET_GROUPS,
payload: null
})
);
};
Component
this is where i keep getting the undefined when i try to use groups.
class GroupList extends Component {
componentDidMount() => {
const {groups} = await this.props.getAllGroups();
this.props.getAllGroups(groups)
}
// Delete account
onDeleteClick = id => {
const { groups } = this.props;
const groupData = {
id: id,
groups: groups
};
this.props.deleteGroup(groupData);
};
render() {
const { user, groups } = this.props;
let groupItems = groups.map(group => (
<li key={group._id} style={{ marginTop: "1rem" }}>
<button
style={{ marginRight: "1rem" }}
onClick={this.onDeleteClick.bind(this, group._id)}
className="btn btn-small btn-floating waves-effect waves-light hoverable red accent-3"
>
<i className="material-icons">delete</i>
</button>
<b>{group.name}</b>
</li>
));
return (
<div>
<Link to="/" className="btn-flat waves-effect">
<i className="material-icons left">keyboard_backspace</i> Back to
home
</Link>
{ { <ul>{groupItems}</ul> } }
</div>
)
}
}
GroupList.propTypes = {
logoutUser: PropTypes.func.isRequired,
getAllGroups: PropTypes.func.isRequired,
// addAccount: PropTypes.func.isRequired,
deleteGroup: PropTypes.func.isRequired,
groups: PropTypes.array.isRequired,
// plaid: PropTypes.object.isRequired,
user: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
groups: state.groups
});
export default connect(
mapStateToProps,
{ getAllGroups, deleteGroup }
)(GroupList);
Getting API resolved without sending a response for /api/contact, this may result in stalled request on the following API route in Next.js. It's using sendgrid and the email gets sent but I'm not getting a response back so I can handle errors or success message.
I've updated the below with the front end code. I'm now not getting that error but on the front end the call 'const response = await fetch('/api/contact'..' doesn't return anything
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_APIKEY);
export default function handler(req, res) {
if (req.method === 'POST') {
const email = {
from: process.env.EMAIL_FROM,
to: process.env.EMAIL_TO,
subject: 'Website Contact Form',
html: `<div>
<div><strong>Name:</strong> ${req.body.name}<br/></div>
<div><strong>Phone:</strong> ${req.body.phone}<br/></div>
<div><strong>Email:</strong> ${req.body.email}<br/></div>
<div><strong>more:</strong> ${req.body.more}<br/></div>
</div>`,
};
try {
return sgMail
.send(email)
.then(() => {
console.log('res1', res);
//return res;
return res.status(200).end();
})
.catch((error) => {
console.log('error', error);
return res.status(500).send(error);
});
} catch (error) {
console.log('error 2', error);
res.json(error);
return res.status(405).end();
}
}
}
import React from 'react';
import { Formik, Form } from 'formik';
import * as Yup from 'yup';
import TextAreaField from './textAreaField';
import TextField from './textfield';
function ContactForm() {
return (
<Formik
initialValues={{
name: '',
phone: '',
email: '',
more: '',
}}
validationSchema={Yup.object({
name: Yup.string().required('Required'),
phone: Yup.string().required('Required'),
email: Yup.string().email('Invalid email address').required('Required'),
more: Yup.string().required('Required'),
})}
onSubmit={async (values, { setSubmitting }) => {
setSubmitting(true);
const response = await fetch('/api/contact', {
body: JSON.stringify({
name: values.name,
phone: values.phone,
email: values.email,
more: values.more,
}),
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
});
console.log('response', response);
const data = await response.json();
console.log('response 1', data);
setSubmitting(false);
}}
>
{(props) => {
const { values, setFieldValue } = props;
console.log('props', props);
console.log('values', values);
return (
<div className="c-contact-form">
<Form className="form">
<TextField label="Customer Name" name="name" type="text" placeholder="John" />
<TextField label="Phone Number" name="phone" type="text" placeholder="07909765432" />
<TextField label="Email Address" name="email" type="email" placeholder="John#gmail.com" />
<TextAreaField label="More" name="more" placeholder="More details" />
<button type="submit" className="c-btn">
Submit
</button>
</Form>
{values.success && (
<div>
<p>Your enquiry has been successfully submitted.</p>
</div>
)}
{values.nosend && (
<div>
<p>OOPS, something went wrong but we know about it. please contact us via email or phone</p>
</div>
)}
</div>
);
}}
</Formik>
);
}
export default ContactForm;
You need to send a response back like the following
try {
sgMail
.send(email)
.then(() => {
console.log('res', res.json);
return res.status(200).end();
})
.catch((error) => {
console.log('error', error);
return res.status(500).send(error);
});
Please I would be happy if anyone would help me
I have a problem, I can not use the server-side functions, I call the functions with axios, and execute it in react hooks.
I actually build chat, which is why I use react hook, because I want messages to be updated all the time.
I also use firestore. There I save the messages, and receive them through the server side function.
It's a component of the chat - it's causing me problems, I do not understand why.
The server side functions work great, I tested them in postman, and they worked. The problem is that I can't run them in a function component. I do not know what I'm doing wrong.
The error I get here is in the line chat.users.length> 0?, When I make this comparison I get that chat.users is undefined, but I do not understand why because I initialize it at first, using a server side function , Which gives the necessary information
I'm very confused, and I'm new here on the site, I'm trying to figure out why it has not worked for two whole days
I think I might be confused by syntax, for example using an unnecessary dispatch inside component of the chat
i got this error:
enter image description here
component of the chat
import React, { useEffect, useState } from 'react';
import './style.css';
import { useDispatch, useSelector } from 'react-redux';
import { getRealtimeUsers, updateMessage, getRealtimeConversations } from '../../redux/actions/chatActions';
import { Fragment } from 'react';
const User = (props) => {
const { chat, onClick } = props;
return (
<div onClick={() => onClick(chat)} className="displayName">
<div className="displayPic">
<img src="https://i.pinimg.com/originals/be/ac/96/beac96b8e13d2198fd4bb1d5ef56cdcf.jpg" alt="" />
</div>
<div style={{ display: 'flex', flex: 1, justifyContent: 'space-between', margin: '0 10px' }}>
<span style={{ fontWeight: 500 }}>{chat.firstName} {chat.lastName}</span>
<span className={chat.isOnline ? `onlineStatus` : `onlineStatus off`}></span>
</div>
</div>
);
}
const HomePage = (props) => {
const dispatch = useDispatch();
const user = useSelector(state => state.user.credentials);
const chat = useSelector(state => state.chat);
const [chatStarted, setChatStarted] = useState(false);
const [chatUser, setChatUser] = useState('');
const [message, setMessage] = useState('');
const [userUid, setUserUid] = useState(null);
let unsubscribe;
useEffect(() => {
//unsubscribe = dispatch(getRealtimeUsers(user.handle))
dispatch(getRealtimeUsers());
}, []);
//console.log(user);
//componentWillUnmount
useEffect(() => {
return () => {
//cleanup
//unsubscribe.then(f => f()).catch(error => console.log(error));
unsubscribe.then(f => f()).catch(error => console.log(error));
}
}, []);
//function
const initChat = (chat) => {
setChatStarted(true)
setChatUser(`${chat.firstName} ${chat.lastName}`)
setUserUid(chat.handle);
console.log(chat);
dispatch(getRealtimeConversations({ uid_1: user.handle, uid_2: chat.handle }));
}
const submitMessage = (e) => {
const msgObj = {
user_uid_1: user.handle,
user_uid_2: userUid,
message
}
if (message !== "") {
dispatch(updateMessage(msgObj))
.then(() => {
setMessage('')
});
}
//console.log(msgObj);
}
return (
<Fragment>
<section className="container">
<div className="listOfUsers">
{console.log(chat)}
{
//chat.users != undefined
chat.users.length > 0 ?
chat.users.map(user => {
return (
<User
onClick={initChat}
key={user.handle}
user={user}
/>
);
})
: null
}
</div>
<div className="chatArea">
<div className="chatHeader">
{
chatStarted ? chatUser : ''
}
</div>
<div className="messageSections">
{
chatStarted ?
chat.conversations.map(con =>
<div style={{ textAlign: con.user_uid_1 == user.handle ? 'right' : 'left' }}>
<p className="messageStyle" >{con.message}</p>
</div>)
: null
}
</div>
{
chatStarted ?
<div className="chatControls">
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Write Message"
/>
<button onClick={submitMessage}>Send</button>
</div> : null
}
</div>
</section>
</Fragment>
);
}
export default HomePage;
This is the axios:
app.get('/realtimeUsers', FBAuth, getRealtimeUsers );
app.post('/updateMessage', FBAuth, updateMessage);
app.get('/realtimeConversations', FBAuth, getRealtimeConversations);
And this is the server side functions - They work 100% - I checked them many times and they worked.:
const { db } = require('../util/admin');
exports.getRealtimeUsers = (req, res) => {
db.collection("users")
.onSnapshot((querySnapshot) => {
const users = [];
querySnapshot.forEach(function (doc) {
if (doc.data().handle != req.user.handle) {
users.push(doc.data());
}
});
return res.json(users);
});
}
exports.updateMessage = (req, res) => {
db.collection('conversations')
.add({
...req.body,
isView: false,
createdAt: new Date()
})
.then(() => {
return res.json({ message: "Conversations added successfully" });
})
.catch((err) => {
console.error(err);
return res.status(500).json({ error: err.code });
});
}
exports.getRealtimeConversations = (req, res) => {
console.log(JSON.stringify("testing"));
console.log(JSON.stringify(req.query));
console.log(JSON.parse(req.query.user));
console.log(JSON.parse(req.query.user).uid_1);
console.log(JSON.parse(req.query.user).uid_2);
db.collection('conversations')
.where('user_uid_1', 'in', [JSON.parse(req.query.user).uid_1, JSON.parse(req.query.user).uid_2])
.orderBy('createdAt', 'asc')
.onSnapshot((querySnapshot) => {
const conversations = [];
querySnapshot.forEach(doc => {
console.log(JSON.stringify(doc));
if (
(doc.data().user_uid_1 == JSON.parse(req.query.user).uid_1 && doc.data().user_uid_2 == JSON.parse(req.query.user).uid_2)
||
(doc.data().user_uid_1 == JSON.parse(req.query.user).uid_2 && doc.data().user_uid_2 == JSON.parse(req.query.user).uid_1)
) {
conversations.push(doc.data())
}
});
console.log(conversations);
return res.json(conversations);
})
//return res.json([]);
}
this is the actions that used in the client side, here i call to the axios:
import { userConstants } from "../types";
import axios from 'axios';
export const getRealtimeUsers = () => (dispatch) => {
dispatch({ type: `${userConstants.GET_REALTIME_USERS}_REQUEST` });
axios
.get('/realtimeUsers')
.then((res) => {
console.log(res);
dispatch({
type: `${userConstants.GET_REALTIME_USERS}_SUCCESS`,
payload: res.data
});
})
.catch((err) => console.log(err))
}
export const updateMessage = (msgObj) => (dispatch) => {
axios.post('/updateMessage', msgObj)
.then(() => { })
.catch((err) => console.log(err));
}
export const getRealtimeConversations = (user) => (dispatch) => {
//user = { uid_1: "from visualcode", uid_2: "userUid" };
console.log(JSON.stringify(user));
axios.get('/realtimeConversations',
{
params: {
user: JSON.stringify(user)
//uid_1:JSON.stringify("user.handle"),
//uid_2:JSON.stringify("userUid")
}
}
)
.then((res) => {
dispatch({
type: userConstants.GET_REALTIME_MESSAGES,
payload: res.data
});
})
.catch((err) => console.log(err))
}
I am not able to understand your whole code flow, i.e., how the chat.users will be populated before initChat is called.
But still, for your problem, you should always put a check for undefined values while iterating through an array.
<div className="listOfUsers">
{console.log(chat)}
{
//chat.users != undefined
chat && chat.users && chat.users.length > 0 &&
chat.users.map(user => {
return (
<User
onClick={initChat}
key={user.handle}
user={user}
/>
);
})
}
</div>
I'm receiving this error: Error: bad content-type header, unknown content-type: text/plain;charset=UTF-8 when trying to upload a photo using Formidable. When I console.log fields and files, I receive two empty objects.
What do I need to change to solve this and upload the photo?
CreatePost.js
const CreatePost = () => {
const [values, setValues] = useState({
title: "",
body: "",
photo: "",
error: "",
createdPost: "",
formData: "",
});
const { user, token } = isAuthenticated();
const {
title,
body,
error,
createdPost,
formData,
} = values;
const handleChange = (name) => (event) => {
const value = name === "photo" ? event.target.files[0] : event.target.value;
setValues({ ...values, [name]: value, formData: new FormData() });
};
const clickSubmit = (event) => {
event.preventDefault();
setValues({ ...values, error: "" });
createPost(user._id, token, formData).then((data) => {
if (data.error) {
setValues({ ...values, error: data.error });
} else {
setValues({
...values,
title: "",
body: "",
photo: "",
createdPost: data.title,
});
}
});
};
const newPostForm = () => (
<form className="mb-3" onSubmit={clickSubmit}>
<h4>Post Photo</h4>
<div className="form-group">
<label className="btn btn-secondary">
<input
onChange={handleChange("photo")}
type="file"
name="photo"
accept="image/*"
/>
</label>
</div>
<div className="form-group">
<label className="text-muted">Title</label>
<input
onChange={handleChange("title")}
type="text"
className="form-control"
value={title}
/>
</div>
<div>
<label>Post body</label>
<textarea
onChange={handleChange("body")}
value={body}
/>
</div>
<button>Create Post</button>
</form>
);
const showError = () => (
<div
style={{ display: error ? "" : "none" }}>
{error}
</div>
);
const showSuccess = () => (
<div
style={{ display: createdPost ? "" : "none" }}>
<h2>{`${createdPost} is created!`}</h2>
</div>
);
return (
<div>
<div>
{showSuccess()}
{showError()}
{newPostForm()}
</div>
</div>
);
};
export default CreatePost;
API request (create post)
export const createPost = (userId, post, token) => {
return fetch(`${API}/blog/post/${userId}`, {
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`
},
body: post
})
.then(response => {
return response.json();
})
.catch(err => {
console.log(err);
});
};
controllers/posts.js
exports.create = (req, res) => {
let form = new formidable()
form.keepExtensions = true
form.parse(req, (err, fields, files) => {
if(err) {
console.log(err)
return res.status(400).json({
error: 'Image could not be uploaded'
})
}
const { title, body } = fields
console.log(fields)
if (!title || !body) {
return res.status(400).json({
error: "All fields are required"
})
}
let post = new Post(fields)
if(files.photo) {
if (files.photo.size > 1000000) {
return res.status(400).json({
error: "Image should be less than 1MB in size."
})
}
post.photo.data = fs.readFileSync(files.photo.path)
post.photo.contentType = files.photo.type
}
post.save((err, result) => {
if(err) {
return res.status(400).json({
error: errorHandler(err)
})
}
res.json(result)
})
})
}
exports.photo = (req, res, next) => {
if (req.post.photo.data) {
res.set('Content-Type', req.post.photo.contentType)
return res.send(req.post.photo.data)
}
next()
}
this has been up for a long time, I bet you already solve it.
If somebody stumbles with this question as I did, what worked for me was adding .IncomingForm() method on the new form in post controller file, like this:
let form = new formidable.IncomingForm();
I have an array of items mapped, and when I delete an item, it deletes in the database, and if I manually refresh the page it is gone. However, I want to "re-render" the list of items, once I click the delete button. From what I can find, is I need a state change to "re-render", so I tried setting up a boolean, but It doesn't "re-render". Any suggestions on best practice to achieve this result would be helpful.
class Profile extends Component {
state = {
username: '',
movies: [],
reRender: false <---- by changing this state, I want a re-render of the component
}
getUserMovies = () => {
const token = localStorage.usertoken;
const decoded = jwt_decode(token);
axios.post('/getusermovies', {
user: decoded.username
}).then(response => {
this.setState({
username: decoded.username,
// movieName: response.data.moviename
movies: response.data
})
console.log(response.data)
}).catch(error => {
console.log(error + "err in the front end getusermovies function")
})
}
componentDidMount() {
this.getUserMovies();
}
deleteMovie = (itemId) => {
axios.post('/delete', {
movie: itemId
}).catch(err => {
console.log(err + "in the deleteMovie function in front end" + itemId)
})
this.setState(prevState => ({
reRender: !prevState.reRender <------ This is where I am calling a state.
}))
}
render() {
let movies = this.state.movies;
return (
<div className="container">
<h1>{this.state.username}'s Movies: </h1>
<div className="row">
{movies.map(item =>
<div className="profile-movies-box" >
<img src={item.movie} alt='no image' className="movies-box-img" />
<h4>{item.moviename}</h4>
<button className="movie-buttons">
<Link to={{
pathname: `/movie?movieName=${item.moviename}`,
state: { link: item.moviename }
}}>View Movie</Link>
</button>
<button
className="movie-btn"
value={item.moviename}
onClick={() => { this.deleteMovie(item.moviename) }}
>Delete Movie</button>
</div>
)}
</div>
</div>
);
}
}
export default Profile;
You need to update movies array, remove item that has been deleted
deleteMovie = (itemId) => {
axios.post('/delete', {
movie: itemId
})
.then(res => {
this.setState(prevState => ({
movies: prevState.movies.filter(m => m.id !== itemId)
}));
})
.catch(err => {
console.log(err + "in the delteMovie function in front end" + itemId)
})
}
I would recommend using async await
deleteMovie = async (itemId) => {
try {
await axios.post('/delete', {
movie: itemId
});
this.setState(prevState => ({
movies: prevState.movies.filter(m => m.id !== itemId)
}));
} catch (err) {
console.log(err + "in the delteMovie function in front end" + itemId)
}
}