Have a Handler Change Value of a Variable in Mongodb - node.js

I am working on a product where I have pre orders and normal orders. For my pre order items, I have the variable pre_orderQty, and for my normal items, I have the variable qty. In my OrderScreen.js, I have a handler that deals with if an order has been shipped (shipHandler). The issue that I am having is that I am trying to get this handler to also update any items in my order that have a qty value of 0 to the value of the pre_orderQty when clicked.
I am using node in my backend and react in my frontend. The orders are stored in mongodb. I'm not exactly sure how to do this, and I would really appreciate any help or advice on how to accomplish this.
So far, I have attempted to do this by:
In my backend orderRouter.js
orderRouter.put(
'/:id/updated',
isAuth,
isAdmin,
expressAsyncHandler(async (req, res) => {
const order = await Order.findById(req.params.id);
if (order && order.orderItems.qty === 0) {
order.orderItems.qty = order.orderItems.pre_orderQty;
order.orderItems.pre_orderQty = 0;
const updatedOrder = await order.save();
res.send({ message: 'Order Updated', order: updatedOrder });
} else {
res.status(404).send({ message: 'Order Not Found' });
}
}),
);
Frontend:
OrderActions.js
export const updateOrder = (orderId) => async (dispatch, getState) => {
dispatch({ type: ORDER_UPDATE_REQUEST, payload: orderId });
const {
userSignin: { userInfo },
} = getState();
try {
const { data } = Axios.put(
`/api/orders/${orderId}/updated`,
{},
{
headers: { Authorization: `Bearer ${userInfo.token}` },
},
);
dispatch({ type: ORDER_UPDATE_SUCCESS, payload: data });
} catch (error) {
const message = error.response && error.response.data.message ? error.response.data.message : error.message;
dispatch({ type: ORDER_UPDATE_FAIL, payload: message });
}
};
OrderScreen
import Axios from 'axios';
import { PayPalButton } from 'react-paypal-button-v2';
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import {shipOrder, deliverOrder, detailsOrder, payOrder, updateOrder } from '../actions/orderActions';
import LoadingBox from '../components/LoadingBox';
import MessageBox from '../components/MessageBox';
import {
ORDER_DELIVER_RESET,
ORDER_SHIPPED_RESET,
ORDER_RETURN_RESET,
ORDER_PAY_RESET,
} from '../constants/orderConstants';
export default function OrderScreen(props) {
const orderId = props.match.params.id;
const [sdkReady, setSdkReady] = useState(false);
const orderDetails = useSelector((state) => state.orderDetails);
const { order, loading, error } = orderDetails;
const userSignin = useSelector((state) => state.userSignin);
const { userInfo } = userSignin;
const orderShip = useSelector((state) => state.orderShip);
const {
loading: loadingShip,
error: errorShip,
success: successShip,
} = orderShip;
const orderUpdate = useSelector((state) => state.orderUpdate);
const {
loading: loadingUpdate,
error: errorUpdate,
success: successUpdate,
} = orderUpdate;
const dispatch = useDispatch();
useEffect(() => {
if (
!order ||
successShip ||
successUpdate ||
(order && order._id !== orderId)
) {
dispatch({ type: ORDER_SHIPPED_RESET });
dispatch({ type: ORDER_UPDATE_RESET });
dispatch(detailsOrder(orderId));
} else {
if (!order.isPaid) {
if (!window.paypal) {
addPayPalScript();
} else {
setSdkReady(true);
}
}
}
}, [dispatch, order, orderId, sdkReady, successShip, successUpdate, order]);
const shipHandler = () => {
dispatch(shipOrder(order._id));
dispatch(updateOrder(order._id));
};
return loading ? (
<LoadingBox></LoadingBox>
) : error ? (
<MessageBox variant="danger">{error}</MessageBox>
) : (
<div>
<h1>Order {order._id}</h1>
<div className="row top">
<div className="col-1">
<div className="card card-body">
<ul>
{userInfo.isAdmin && (
<li>
{loadingShip && <LoadingBox></LoadingBox>}
{errorShip && (
<MessageBox variant="danger">{errorShip}</MessageBox>
)}
<button
type="button"
className="primary block"
onClick={shipHandler}
>
Order Shipped
</button>
</li>
)}
</ul>
</div>
</div>
</div>
</div>
);
}

Related

Loading set to true, reducer dispatch stuck at request after few renders of application. Need to re-run every time it stuck like this [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed yesterday.
Improve this question
Creating a react application with nodejs backend power with redux for state management. After i run my application for few renders all the dispatches are running as it supposed to be but after a point...loading is set true forever. I need to re-run the application from commandline and again same issue. would like to know what's the problem.
My UserActions:
import axios from 'axios'
import { BOT_DETAILS_RESET, BOT_LIST_RESET } from '../constants/botConstants'
import { USER_CREATE_FAILURE, USER_CREATE_REQUEST, USER_CREATE_SUCCESS, USER_DELETE_FAILURE, USER_DELETE_REQUEST, USER_DELETE_SUCCESS, USER_DETAILS_FAILURE, USER_DETAILS_REQUEST, USER_DETAILS_RESET, USER_DETAILS_SUCCESS, USER_LIST_FAILURE, USER_LIST_REQUEST, USER_LIST_RESET, USER_LIST_SUCCESS, USER_LOGIN_FAILURE, USER_LOGIN_REQUEST, USER_LOGIN_SUCCESS, USER_LOGOUT, USER_UPDATE_FAILURE, USER_UPDATE_REQUEST, USER_UPDATE_SUCCESS } from "../constants/userConstants"
export const login = (username, password) => async (dispatch) => {
try {
dispatch({
type: USER_LOGIN_REQUEST
})
const config = {
header: {
'Content-Type': 'application/json',
}
}
const { data } = await axios.post('/api/users/login', { username, password }, config)
dispatch({
type: USER_LOGIN_SUCCESS,
payload: data
})
localStorage.setItem('userInfo', JSON.stringify(data))
} catch (error) {
dispatch({
type: USER_LOGIN_FAILURE,
payload: error.response && error.response.data.message ? error.response.data.message : error.message
})
}
}
export const listUsers = () => async (dispatch, getState) => {
try {
dispatch({
type: USER_LIST_REQUEST
})
const { userLogin: { userInfo } } = getState()
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.get(`/api/users`, config)
console.log(data)
dispatch({
type: USER_LIST_SUCCESS,
payload: data.users_list
})
} catch (error) {
const message =
error.response && error.response.data.message
? error.response.data.message
: error.message
if (message === 'Not authorized, token failed') {
dispatch(logout())
}
dispatch({ type: USER_LIST_FAILURE, payload: message })
}
}
export const deleteUser = (username) => async (dispatch, getState) => {
try {
dispatch({
type: USER_DELETE_REQUEST
})
const { userLogin: { userInfo } } = getState()
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`
}
}
await axios.delete(`/api/users/${username}`, config)
dispatch({
type: USER_DELETE_SUCCESS,
})
} catch (error) {
const message = error.response && error.response.data.message ? error.response.data.message : error.message
if (message === 'Not authorized, token failed') {
dispatch(logout())
}
dispatch({ type: USER_DELETE_FAILURE, payload: message })
}
}
export const createUser = (first_name, last_name, username, password, role) => async (dispatch, getState) => {
const newRole = role.toUpperCase()
console.log(newRole)
try {
dispatch({
type: USER_CREATE_REQUEST
})
const { userLogin: { userInfo } } = getState()
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.post(`/api/users/`, { first_name, last_name, username, password, role: newRole }, config)
console.log(data)
dispatch({
type: USER_CREATE_SUCCESS,
payload: data
})
} catch (error) {
dispatch({ type: USER_CREATE_FAILURE, payload: error.response && error.response.data.message ? error.response.data.message : error.message })
}
}
export const getUserDetails = (username) => async (dispatch, getState) => {
try {
dispatch({
type: USER_DETAILS_REQUEST
})
const { userLogin: { userInfo } } = getState()
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.get(`/api/users/${username}`, config)
dispatch({
type: USER_DETAILS_SUCCESS,
payload: data
})
} catch (error) {
const message =
error.response && error.response.data.message
? error.response.data.message
: error.message
if (message === 'Not authorized, token failed') {
dispatch(logout())
}
dispatch({ type: USER_DETAILS_FAILURE, payload: message })
}
}
export const updateUser = (user, username) => async (dispatch, getState) => {
try {
dispatch({
type: USER_UPDATE_REQUEST
})
const { userLogin: { userInfo } } = getState()
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${userInfo.token}`
}
}
const { data } = await axios.put(`/api/users/${username}`, user, config)
dispatch({
type: USER_UPDATE_SUCCESS,
})
dispatch({
type: USER_DETAILS_SUCCESS,
payload: data
})
} catch (error) {
const message =
error.response && error.response.data.message
? error.response.data.message
: error.message
if (message === 'Not authorized, token failed') {
dispatch(logout())
}
dispatch({ type: USER_UPDATE_FAILURE, payload: message })
}
}
export const logout = () => (dispatch) => {
localStorage.removeItem('userInfo')
dispatch({ type: USER_DETAILS_RESET })
dispatch({ type: BOT_DETAILS_RESET })
dispatch({ type: USER_LIST_RESET })
dispatch({ type: BOT_LIST_RESET })
dispatch({ type: USER_LOGOUT })
document.location.href = '/'
}
My user Reducer:
export const userLoginReducer = (state = {}, action) => {
switch (action.type) {
case USER_LOGIN_REQUEST:
return { loading: true }
case USER_LOGIN_SUCCESS:
return { loading: false, userInfo: action.payload }
case USER_LOGIN_FAILURE:
return { loading: false, error: action.payload }
case USER_LOGOUT:
return {}
default:
return state
}
}
export const userListReducer = (state = { users: [] }, action) => {
switch (action.type) {
case USER_LIST_REQUEST:
return { loading: true, }
case USER_LIST_SUCCESS:
return { loading: false, users: action.payload }
case USER_LIST_FAILURE:
return { loading: false, error: action.payload }
case USER_LIST_RESET:
return { users: [] }
default:
return state
}
}
export const userDeleteReducer = (state = {}, action) => {
switch (action.type) {
case USER_DELETE_REQUEST:
return { loading: true, }
case USER_DELETE_SUCCESS:
return { loading: false, success: true }
case USER_DELETE_FAILURE:
return { loading: false, error: action.payload }
default:
return state
}
}
export const userCreateReducer = (state = {}, action) => {
switch (action.type) {
case USER_CREATE_REQUEST:
return { loading: true, }
case USER_CREATE_SUCCESS:
return { loading: false, success: true, user: action.payload }
case USER_CREATE_FAILURE:
return { loading: false, error: action.payload }
case USER_CREATE_RESET:
return {}
default:
return state
}
}
export const userDetailsReducer = (state = { user: {} }, action) => {
switch (action.type) {
case USER_DETAILS_REQUEST:
return { ...state, loading: true, }
case USER_DETAILS_SUCCESS:
return { loading: false, user: action.payload }
case USER_DETAILS_FAILURE:
return { loading: false, error: action.payload }
case USER_DETAILS_RESET:
return { user: {} }
default:
return state
}
}
export const userUpdateReducer = (state = { user: {} }, action) => {
switch (action.type) {
case USER_UPDATE_REQUEST:
return { loading: true, }
case USER_UPDATE_SUCCESS:
return { loading: false, success: true }
case USER_UPDATE_FAILURE:
return { loading: false, error: action.payload }
case USER_UPDATE_RESET:
return { user: {} }
default:
return state
}
}
My Login Component:
import React, { useEffect, useState } from 'react'
import COLOR from '../const/colors'
import { Row, Col, Space, Typography, Form, Button, Input } from 'antd'
import { Link, useNavigate } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { login } from '../redux/actions/userActions'
const { Title } = Typography
const LoginPage = () => {
const dispatch = useDispatch()
const navigate = useNavigate()
const [input, setInput] = useState({
username: '',
password: ''
})
const userLogin = useSelector(state => state.userLogin)
const { loading, userInfo, error } = userLogin
const handleChange = (e) => {
const { name, value } = e.target
setInput({
...input,
[name]: value
})
}
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
const handleSubmit = () => {
dispatch(login(input.username, input.password))
console.log('login request dispatched')
}
useEffect(() => {
if (userInfo) {
navigate('/auth')
}
}, [userInfo, dispatch, navigate])
return (
<div>
{loading && <p>Loading...</p>}
{error && <p>{error}</p>}
<Row gutter={[0, { xs: 8, sm: 16, md: 24, lg: 32 }]}>
<Col className="gutter-row"
xs={{ span: 20, offset: 2 }}
sm={{ span: 16, offset: 4 }}
md={{ span: 14, offset: 6 }}
lg={{ span: 14, offset: 6 }}
xl={{ span: 6, offset: 9 }}>
<Row justify="center" align="middle">
<Col span={24}>
<Space direction="vertical" className="container-login">
<Title level={4}
style={{
color: COLOR.PRIMARY,
textAlign: "center",
fontWeight: "bold",
marginTop: 20,
}}>
Sign in to Damex CWC
</Title>
<br />
<Form
name="normal-login"
className='login-form'
onFinish={handleSubmit}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
{/* <Spin
spinning={loading}
size="large"
indicator={
<LoadingOutlined style={{ color: "#00ff6a" }} />
}
> */}
<Form.Item
rules={[
{
required: true,
message: "Please input your Username"
},
{
type: "username",
message: "Please enter a valid email address",
},
]}
>
<Input
name='username'
size="large"
placeholder={"Username"}
value={input.username}
onChange={handleChange}
/>
</Form.Item>
<Form.Item
rules={[
{
required: true,
message: "Please input your Password",
},
]}
>
<Input.Password
name='password'
size="large"
placeholder={"Password"}
value={input.password}
onChange={handleChange}
/>
</Form.Item>
{/* <Form.Item
name="remember"
valuePropName="checked"
>
<Checkbox>Remember me</Checkbox>
</Form.Item> */}
<Form.Item
>
<Button
block
type="primary"
htmlType="submit"
className="login-form-button"
>
Sign In
</Button>
</Form.Item>
{/* </Spin> */}
</Form>
</Space>
</Col>
</Row>
<br />
<Row
justify="center" align="middle"
>
<Button
className="link-login"
type="link"
>
<Link className='link-login' to={"/forgotpassword"}>
Forgot password?
</Link>
</Button>
<span>{"‧"}</span>
<Button
className="link-login"
type="link"
>
<Link className='link-login' to={"#"}
onClick={(e) => {
window.location = "mailto:info#damex.io";
e.preventDefault();
}}
>
Don't have an account?
</Link>
</Button>
<span>{"‧"}</span>
<Button type="link" className="link-login" >
<Link
className="link-login"
to="https://www.damex.io/privacy"
target="_blank"
rel="noopener noreferrer"
>
Privacy Policy
</Link>
</Button>
</Row>
<Row justify="center" align="middle">
<Link to="mailto:support#damex.io?subject=Issue with 2FA (Damex Business)">
<Button type="link" className="link-login">
Have an issue with 2-factor authentication?
</Button>
</Link>
</Row>
</Col>
</Row>
</div>
)
}
export default LoginPage
My userList page:
import { Button, Col, Row } from 'antd'
import React, { useEffect, useState, } from 'react'
import COLOR from '../const/colors'
import { useDispatch, useSelector } from 'react-redux'
import { useNavigate } from 'react-router-dom'
import { deleteUser, listUsers } from '../redux/actions/userActions'
import Table from '../components/Table'
import ModalDelete from '../components/ModalDelete'
const UserListPage = () => {
const dispatch = useDispatch()
const navigate = useNavigate()
const userLogin = useSelector(state => state.userLogin)
const { userInfo } = userLogin
console.log(userInfo.role)
const userList = useSelector(state => state.userList)
const { loading, error, users } = userList
const userDelete = useSelector(state => state.userDelete)
const { success: successDelete } = userDelete
const [selectedUser, setSelectedUser] = useState(null);
const [modalVisible, setModalVisible] = useState(false);
const handleCreate = () => {
navigate(`/auth/users/create`)
};
useEffect(() => {
if ((userInfo && (userInfo.role === 'ADMIN' || userInfo.role === 'TRADING'))) {
dispatch(listUsers())
} else {
navigate('/')
}
}, [dispatch, userInfo, successDelete, navigate])
// handle delete button click
const handleDelete = (user) => {
setSelectedUser(user);
setModalVisible(true);
};
// handle modal confirm delete
const handleConfirmDelete = () => {
// dispatch delete user by username action
dispatch(deleteUser(selectedUser.username));
setModalVisible(false);
};
// handle modal cancel delete
const handleCancelDelete = () => {
setSelectedUser(null);
setModalVisible(false);
};
return (
<div style={{ padding: '0 1rem' }}>
{userInfo && (userInfo.role === 'ADMIN' || userInfo.role === 'TRADING') ? (
<>
<div style={{ color: COLOR.SECONDARY_TEXT, marginBottom: '32px', marginTop: '24px' }}>
Users
</div>
<Row style={{ margin: '24px' }}>
<Col offset={20}>
<Button type='primary' onClick={handleCreate} className='create-btn'>Create User</Button>
</Col>
</Row>
<Table users={users} handleDelete={handleDelete} />
{loading && <p>Loading...{loading}</p>}
{error && <p>{error}</p>}
</>
) :
<p>Not Authorized to view this</p>
}
<ModalDelete
user={selectedUser}
isModalOpen={modalVisible}
onConfirm={handleConfirmDelete}
onCancel={handleCancelDelete}
/>
</div>
)
}
export default UserListPage
Table component:
import React from 'react'
import { Table as AntdTable, Button, Space } from 'antd'
import { useNavigate } from 'react-router-dom';
const Table = ({ users, bots, handleDelete }) => {
console.log(users && users)
console.log(bots && bots)
const navigate = useNavigate()
const handleEdit = (record) => {
users && navigate(`/auth/users/${record.username}`);
bots && navigate(`/auth/bots/${record.bot_id}`);
};
let columns = [];
if (users) {
columns = [{ key: 'username', title: 'Username', dataIndex: 'username' }, { key: 'role', title: 'Role', dataIndex: 'role' }]
} else if (bots) {
columns = [
{ key: 'bot_id', title: 'BotID', dataIndex: 'bot_id' },
{ key: 'exchange', title: 'Exchange', dataIndex: 'exchange' },
{ key: 'strategy', title: 'Strategy', dataIndex: 'strategy' },
{ key: 'trading_pair', title: 'Trading Pair', dataIndex: 'trading_pair' },
]
}
const actionColumn = {
title: 'Action',
dataIndex: 'id',
key: 'action',
render: (id, record) => (
<Space size={'large'}>
<Button type="primary" onClick={() => handleEdit(record)}>Edit</Button>
<Button type="primary" className='danger-btn' onClick={() => handleDelete(record)}>Delete</Button>
</Space>
),
};
const tableColumns = [
...columns,
actionColumn,
];
return (
<AntdTable rowKey={record => users ? record.username : record.bot_id} dataSource={users ? users : bots} columns={tableColumns} />
)
}
export default Table
I couldn't figure out what's wrong...if it's problem with front end it shouldn't be working with starting few renders of application right. In case backend controller here it is:
import asyncHandler from 'express-async-handler'
import generateToken from '../utils/generateToken.js'
import pool from '../config/db.js'
import bcrypt from 'bcryptjs'
//Auth user & get token
// Post /api/users/login
// Public route
export const authUser = asyncHandler(async (req, res) => {
console.log('logging...')
const { username, password } = req.body
try {
const query = `SELECT * FROM users WHERE username = '${username}';`
const client = await pool.connect()
const user = await client.query(query);
client.release();
if (user.rows.length !== 0) {
const user_info = user.rows[0];
const matchedPassword = await bcrypt.compare(password, user_info.password);
if (matchedPassword) {
res.status(200).json({
username: user_info.username,
role: user_info.role,
token: generateToken(user_info.username)
});
} else {
res.status(401).json({ message: 'Invalid email or password! Please, try again' });
}
} else {
res.status(401).json({ message: 'Invalid email or password! Please, try again' });
}
} catch (error) {
res.status(500).json({ message: 'Server error has occurred', error: error })
}
})
// //get user profile
// // GET /api/users/profile
// // Private route
export const getUserProfile = asyncHandler(async (req, res) => {
try {
const user_profile_query = `SELECT username, first_name, last_name, role FROM users WHERE username = '${req.username}';`
const client = await pool.connect();
const results = await client.query(user_profile_query);
client.release();
if (results.rows.length !== 0) {
const user_profile = results.rows[0]
res.status(200).json({ user_profile });
}
else {
res.status(404).json({ message: `User Not Found for ${req.username}` });
}
} catch (error) {
res.status(500).json({ message: `Internal Server Error while fetching user - ${req.username}.`, error: error })
}
})
// //put update user password
// // PUT /api/users/profile
// // Private route
export const updateUserPassword = asyncHandler(async (req, res) => {
try {
const updatedHashedPassword = await bcrypt.hash(req.body.password, 10);
const user_password_update_query = `UPDATE users SET password = '${updatedHashedPassword}' WHERE username = '${req.username}' RETURNING username, first_name, last_name, role;`
const client = await pool.connect();
const results = await client.query(user_password_update_query);
client.release();
if (results.rows.length !== 0) {
const user_password_update = results.rows[0]
res.status(200).json({ user_password_update });
}
else {
res.status(404).json({ message: `User Not Found for ${req.username}` });
}
} catch (error) {
res.status(500).json({ message: `Internal Server Error while updating password for user - ${req.username}.`, error: error })
}
})
//Register a new user
// Post /api/users
// Private/Admin route
export const registerUser = asyncHandler(async (req, res) => {
console.log('registering...')
try {
const { username, first_name, last_name, password, role } = req.body
const user_exist_query = `SELECT * FROM users WHERE username = '${username}';`
const client = await pool.connect();
const user_exists = await client.query(user_exist_query);
if (user_exists.rows.length !== 0) {
return res.status(400).json({ message: `User - ${username} already exists.` })
}
const hashedPassword = await bcrypt.hash(password, 10);
const user_register_query = 'INSERT INTO users (username, first_name, last_name, password, role) VALUES ($1, $2, $3, $4, $5) RETURNING username, first_name, last_name, role;';
const values = [username, first_name, last_name, hashedPassword, role]
const results = await client.query(user_register_query, values);
client.release();
if (results.rows.length !== 0) {
const user_info = results.rows[0];
res.status(201).json({
username: user_info.username,
role: user_info.role,
})
} else {
res.status(400).json({ message: `Invalid user data for registering user - ${username}` })
}
} catch (error) {
res.status(500).json({ message: `Internal Server Error while registering user - ${username}.`, error: error })
}
})
//get all users
// GET /api/users
// Private/admin route
export const getUsers = asyncHandler(async (req, res) => {
try {
const users_list_query = `SELECT username, first_name, last_name, role FROM users;`
const client = await pool.connect();
const results = await client.query(users_list_query);
client.release();
if (results.rows.length !== 0) {
const users_list = results.rows
res.status(200).json({ users_list });
}
else {
res.status(404).json({ message: `No users found.` });
}
} catch (error) {
res.status(500).json({ message: `Internal Server Error while fetching users list}.`, error: error })
}
})
//delete a user by id
// delete /api/users/:id
// Private/admin route
export const deleteUser = asyncHandler(async (req, res) => {
try {
const user_delete_query = `DELETE FROM users WHERE username = '${req.params.username}';`
const client = await pool.connect();
const user_delete = await client.query(user_delete_query);
client.release();
if (user_delete.rowCount !== 0) {
res.status(200).json({ message: 'User removed from Database successfully.' });
}
else {
res.status(404).json({ message: `User Not Found for ${req.params.username}` });
}
} catch (error) {
res.status(500).json({ message: `Internal Server Error while deleting user - ${req.params.username}.`, error: error })
}
})

Why do I have to refresh the page when I delete a post? MERN stack

I am a beginner in the MERN stack and I am interested in why I have to refresh the page after deleting the document (post)?
This is my Action.js
export const deletePost = id => async (dispatch, getState) => {
try {
dispatch({ type: DELETE_POST_BEGIN });
const {
userLogin: { userInfo },
} = getState();
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`,
},
};
const { data } = await axios.delete(`/api/v1/post/${id}`, config);
dispatch({ type: DELETE_POST_SUCCESS, payload: data });
} catch (error) {
dispatch({
type: DELETE_POST_FAIL,
payload: { msg: error.response.data.msg },
});
}
};
This is my Reducer.js
export const deletePostReducer = (state = {}, action) => {
switch (action.type) {
case DELETE_POST_BEGIN:
return { loading: true };
case DELETE_POST_SUCCESS:
return { loading: false };
case DELETE_POST_FAIL:
return { loading: false, error: action.payload.msg };
default:
return state;
}
};
And this is my Home page where i list all posts:
import { useEffect } from 'react';
import { Col, Container, Row } from 'react-bootstrap';
import { useDispatch, useSelector } from 'react-redux';
import { getPosts } from '../actions/postActions';
import Loader from '../components/Loader';
import Message from '../components/Message';
import Post from '../components/Post';
const HomePage = () => {
const dispatch = useDispatch();
const allPosts = useSelector(state => state.getPosts);
const { loading, error, posts } = allPosts;
const deletePost = useSelector(state => state.deletePost);
const { loading: loadingDelete } = deletePost;
useEffect(() => {
dispatch(getPosts());
}, [dispatch]);
return (
<Container>
{loading || loadingDelete ? (
<Loader />
) : error ? (
<Message variant='danger'>{error}</Message>
) : (
<>
<Row>
{posts.map(post => (
<Col lg={4} key={post._id} className='mb-3'>
<Post post={post} />
</Col>
))}
</Row>
</>
)}
</Container>
);
};
export default HomePage;
And this is my single Post component:
const Post = ({ post }) => {
const dispatch = useDispatch();
const allPosts = useSelector(state => state.getPosts);
const { loading, error, posts } = allPosts;
const userLogin = useSelector(state => state.userLogin);
const { userInfo } = userLogin;
const handleDelete = id => {
dispatch(deletePost(id));
};
return (
<>
<div>{post.author.username}</div>
<Card>
<Card.Img variant='top' />
<Card.Body>
<Card.Title>{post.title}</Card.Title>
<Card.Text>{post.content}</Card.Text>
<Button variant='primary'>Read more</Button>
{userInfo?.user._id == post.author._id && (
<Button variant='danger' onClick={() => handleDelete(post._id)}>
Delete
</Button>
)}
</Card.Body>
</Card>
</>
);
};
And my controller:
const deletePost = async (req, res) => {
const postId = req.params.id;
const post = await Post.findOne({ _id: postId });
if (!post.author.equals(req.user.userId)) {
throw new BadRequestError('You have no permission to do that');
}
await Post.deleteOne(post);
res.status(StatusCodes.NO_CONTENT).json({
post,
});
};
I wish someone could help me solve this problem, it is certainly something simple but I am a beginner and I am trying to understand.
I believe the issue is that you are not fetching the posts after delete is successful.
Try this inside the HomePage component:
...
const [isDeleting, setIsDeleting] = useState(false);
const { loading: loadingDelete, error: deleteError } = deletePost;
useEffect(() => {
dispatch(getPosts());
}, [dispatch]);
useEffect(() => {
if (!deleteError && isDeleting && !loadingDelete) {
dispatch(getPosts());
}
setIsDeleting(loadingDelete);
}, [dispatch, deleteError, isDeleting, loadingDelete]);
...
Another method is to use "filtering", but you have to update your reducer as such:
export const deletePostReducer = (state = {}, action) => {
switch (action.type) {
case DELETE_POST_BEGIN:
return { loading: true };
case DELETE_POST_SUCCESS:
return { loading: false, data: action.payload}; // <-- this was changed
case DELETE_POST_FAIL:
return { loading: false, error: action.payload.msg };
default:
return state;
}
};
Now in your HomePage component, you will do something like this when rendering:
...
const { loading: loadingDelete, data: deletedPost } = deletePost;
...
useEffect(() => {
dispatch(getPosts());
if (deletedPost) {
console.log(deletedPost);
}
}, [dispatch, deletedPost]);
return (
...
<Row>
{posts.filter(post => post._id !== deletedPost?._id).map(post => (
<Col lg={4} key={post._id} className='mb-3'>
<Post post={post} />
</Col>
))}
</Row>
)

Builds a chat app in React, using axios and firestore

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>

_id is missing after doing actions

i'm currently creating my first MERN App, and everything is going well, until something happened, and i'm going my try to explain because i need help !
What i'm doing is a facebook clone, where you can post something, you can delete your post and you can update your post, the logic is simple, i call dispatch to pass the data to the actions, the actions pass the data to the backend, and the backend return something to me and it saves in my store, because i'm using redux
The problem is that, when i have 2 post, and i want to delete a post, or maybe i want to edit it, the other post dissapears, it's like it loses its id and then loses the information, then i can't do anything but reaload the page, and it happens always
this is how it looks like, everything fine
Then, after trying to edit a post, the second one lost its information, and in the console, it says that Warning: Each child in a list should have a unique "key" prop, and i already gave each post the key={_id}, but the post lost it and i don't know how
Here's the code
Posts.js
import React, { useState } from "react";
import "./Posts.css";
import moment from "moment";
// Icons
import { BiDotsVertical, BiLike } from "react-icons/bi";
import { MdDeleteSweep } from "react-icons/md";
import { AiFillLike } from "react-icons/ai";
import { GrClose } from "react-icons/gr";
// Calling actions
import { deletePost, } from "../actions/posts.js";
// Gettin The Data From Redux
import { useSelector, useDispatch } from "react-redux";
const Posts = ({ setCurrentId }) => {
const [animation, setAnimation] = useState(false);
const [modal, setModal] = useState(false);
const [modalPost, setModalPost] = useState({});
// Getting The Posts
const posts = useSelector(state => state.posts);
const dispatch = useDispatch();
// Showing And Hiding Modal Window
const ModalWindow = post => {
setModalPost(post);
setModal(true);
};
// Liking the post
// const Like = id => {
// dispatch(giveLike(id));
// setAnimation(!animation);
// };
if (!posts.length) {
return <div>Loading</div>;
} else {
return (
<div className="Posts">
{/* // Modal window for better look to the post */}
{/* {modal && (
<div className="modalWindow">
<div className="container">
<div className="container-image">
<img src={modalPost.image} alt="" />
</div>
<div className="information">
<div className="container-information">
<div className="data-header">
<h2>
User <br />{" "}
<span style={{ fontWeight: "400" }}>
{moment(modalPost.createdAt).fromNow()}
</span>
</h2>
<span className="data-icon" onClick={() => setModal(false)}>
<GrClose />
</span>
</div>
<div className="message">
<h2>{modalPost.title}</h2>
<p>{modalPost.message}</p>
</div>
</div>
</div>
</div>
</div>
)} */}
{/* */}
{posts.map(post => {
const { _id, title, message, image, createdAt, likes } = post;
return (
<div className="Posts-container" key={_id}>
<div className="Fit">
<div className="Fit-stuff">
<h2 className="Fit-stuff_title">
User <br />{" "}
<span style={{ fontWeight: "400" }}>
{moment(createdAt).fromNow()}
</span>
</h2>
<a
className="Fit-stuff_edit"
href="#form"
onClick={() => setCurrentId(_id)}
>
<BiDotsVertical />
</a>
</div>
<div className="Fit-data">
<h2 className="Fit-data_title">{title}</h2>
<p className="Fit-data_message">{message}</p>
{image ? (
<div className="Fit-img">
<img
onClick={() => ModalWindow(post)}
src={image}
alt=""
/>
</div>
) : (
<div></div>
)}
</div>
<div className="Fit-shit">
<span>
{animation ? (
<AiFillLike className="fullLightBlue" />
) : (
<BiLike />
)}
{likes}
</span>
<span onClick={() => dispatch(deletePost(_id))}>
<MdDeleteSweep />
</span>
</div>
</div>
</div>
);
})}
</div>
);
}
};
export default Posts;
The form where i call update and create Post
import React, { useState, useEffect } from "react";
import Filebase from "react-file-base64";
// For the actions
import { useDispatch, useSelector } from "react-redux";
import { createPost, updatePost } from "../actions/posts.js";
import {
Wrapper,
FormContainer,
Data,
DataInput,
SecondDataInput,
FormContainerImg,
FormContainerButtons,
Buttons
} from "./FormStyled.js";
const Form = ({ currentId, setCurrentId }) => {
const [formData, setFormData] = useState({
title: "",
message: "",
image: ""
});
const specificPost = useSelector(state =>
currentId ? state.posts.find(p => p._id === currentId) : null
);
// Sending The Data And Editing The data
const dispatch = useDispatch();
useEffect(() => {
if (specificPost) setFormData(specificPost);
}, [specificPost]);
// Clear Inputs
const clear = () => {
setCurrentId(0);
setFormData({ title: "", message: "", image: "" });
};
const handleSubmit = async e => {
e.preventDefault();
if (currentId === 0) {
dispatch(createPost(formData));
clear();
} else {
dispatch(updatePost(currentId, formData));
clear();
}
};
return (
<Wrapper>
<FormContainer onSubmit={handleSubmit}>
<Data>
<DataInput
name="title"
maxLength="50"
placeholder="Title"
type="text"
value={formData.title}
onChange={e => setFormData({ ...formData, title: e.target.value })}
/>
<SecondDataInput
name="message"
placeholder="Message"
maxLength="300"
value={formData.message}
required
onChange={e =>
setFormData({ ...formData, message: e.target.value })
}
/>
<FormContainerImg>
<Filebase
required
type="file"
multiple={false}
onDone={({ base64 }) =>
setFormData({ ...formData, image: base64 })
}
/>
</FormContainerImg>
<FormContainerButtons>
<Buttons type="submit" create>
{specificPost ? "Edit" : "Create"}
</Buttons>
<Buttons onClick={clear} clear>
Clear
</Buttons>
</FormContainerButtons>
</Data>
</FormContainer>
</Wrapper>
);
};
export default Form;
My actions
import {
GETPOSTS,
CREATEPOST,
DELETEPOST,
UPDATEPOST,
LIKEPOST
} from "../actionTypes/posts.js";
import * as api from "../api/posts.js";
export const getPosts = () => async dispatch => {
try {
const { data } = await api.getPosts();
dispatch({ type: GETPOSTS, payload: data });
} catch (error) {
console.log(error);
}
};
export const createPost = newPost => async dispatch => {
try {
const { data } = await api.createPost(newPost);
dispatch({ type: CREATEPOST, payload: data });
} catch (error) {
console.log(error);
}
};
export const updatePost = (id, updatePost) => async dispatch => {
try {
const { data } = await api.updatePost(id, updatePost);
dispatch({ type: UPDATEPOST, payload: data });
} catch (error) {
console.log(error);
}
};
export const deletePost = id => async dispatch => {
try {
await api.deletePost(id);
dispatch({ type: DELETEPOST, payload: id });
} catch (error) {
console.log(error);
}
};
Redux Part
import {
GETPOSTS,
CREATEPOST,
DELETEPOST,
UPDATEPOST,
LIKEPOST
} from "../actionTypes/posts.js";
const postData = (posts = [], action) => {
switch (action.type) {
case GETPOSTS:
return action.payload;
case CREATEPOST:
return [...posts, action.payload];
case UPDATEPOST:
return posts.map(post =>
action.payload._id === post._id ? action.payload : posts
);
case DELETEPOST:
return posts.filter(post => post._id !== action.payload);
default:
return posts;
}
};
export default postData;
My controllers in the backend
import mongoose from "mongoose";
import infoPost from "../models/posts.js";
// Getting All The Posts
export const getPosts = async (req, res) => {
try {
const Posts = await infoPost.find();
res.status(200).json(Posts);
} catch (error) {
res.status(404).json({ message: error.message });
console.log(error);
}
};
// Creating A Post
export const createPost = async (req, res) => {
const { title, message, image } = req.body;
const newPost = new infoPost({ title, message, image });
try {
await newPost.save();
res.status(201).json(newPost);
} catch (error) {
res.status(409).json({ message: error.message });
console.log(error);
}
};
// Update A Post
export const updatePost = async (req, res) => {
const { id } = req.params;
const { title, message, image } = req.body;
if (!mongoose.Types.ObjectId.isValid(id))
return res.status(404).send(`No Post With Id Of ${id}`);
const updatedPost = { title, message, image, _id: id };
await infoPost.findByIdAndUpdate(id, updatedPost, { new: true });
res.json(updatedPost);
};
// Deleting A Post
export const deletePost = async (req, res) => {
const { id } = req.params;
if (!mongoose.Types.ObjectId.isValid(id))
return res
.status(404)
.send(`We Couldnt Found The Post With Id Of ${id} To Delete`);
await infoPost.findByIdAndRemove(id);
res.json(`Post With Id Of ${id} Deleted Succesfully`);
};
// Liking A Post
export const likePost = async (req, res) => {
const { id } = req.params;
if (!mongoose.Types.ObjectId.isValid(id))
return res.status(404).send(`No post with id: ${id}`);
const post = await infoPost.findById(id);
const updatedPost = await infoPost.findByIdAndUpdate(
id,
{ likeCount: post.likeCount + 1 },
{ new: true }
);
res.json(updatedPost);
};
Even though i've been trying to solve this problem for nearly 3.5 hours, i think that the problem might be in my Posts.js part, if you can help me, you're the greatest !

How to update the user feed after updating the post?

I have a UserFeed component and EditForm component. As soon as I edit the form, I need to be redirected to the UserFeed and the updated data should be shown on UserFeed(title and description of the post).
So, the flow is like-UserFeed, which list the posts, when click on edit,redirected to EditForm, updates the field, redirected to UserFeed again, but now UserFeed should list the posts with the updated data, not the old one.
In this I'm just redirectin to / just to see if it works. But I need to be redirected to the feed with the updated data.
EditForm
import React, { Component } from "react";
import { connect } from "react-redux";
import { getPost } from "../actions/userActions"
class EditForm extends Component {
constructor() {
super();
this.state = {
title: '',
description: ''
};
handleChange = event => {
const { name, value } = event.target;
this.setState({
[name]: value
})
};
componentDidMount() {
const id = this.props.match.params.id
this.props.dispatch(getPost(id))
}
componentDidUpdate(prevProps) {
if (prevProps.post !== this.props.post) {
this.setState({
title: this.props.post.post.title,
description: this.props.post.post.description
})
}
}
handleSubmit = () => {
const id = this.props.match.params.id
const data = this.state
this.props.dispatch(updatePost(id, data, () => {
this.props.history.push("/")
}))
}
render() {
const { title, description } = this.state
return (
<div>
<input
onChange={this.handleChange}
name="title"
value={title}
className="input"
placeholder="Title"
/>
<textarea
onChange={this.handleChange}
name="description"
value={description}
className="textarea"
></textarea>
<button>Submit</button>
</div>
);
}
}
const mapStateToProps = store => {
return store;
};
export default connect(mapStateToProps)(EditForm)
UserFeed
import React, { Component } from "react"
import { getUserPosts, getCurrentUser } from "../actions/userActions"
import { connect } from "react-redux"
import Cards from "./Cards"
class UserFeed extends Component {
componentDidMount() {
const authToken = localStorage.getItem("authToken")
if (authToken) {
this.props.dispatch(getCurrentUser(authToken))
if (this.props && this.props.userId) {
this.props.dispatch(getUserPosts(this.props.userId))
} else {
return null
}
}
}
render() {
const { isFetchingUserPosts, userPosts } = this.props
return isFetchingUserPosts ? (
<p>Fetching....</p>
) : (
<div>
{userPosts &&
userPosts.map(post => {
return <Cards key={post._id} post={post} />
})}
</div>
)
}
}
const mapStateToPros = state => {
return {
isFetchingUserPosts: state.userPosts.isFetchingUserPosts,
userPosts: state.userPosts.userPosts.userPosts,
userId: state.auth.user._id
}
}
export default connect(mapStateToPros)(UserFeed)
Cards
import React, { Component } from "react"
import { connect } from "react-redux"
import { compose } from "redux"
import { withRouter } from "react-router-dom"
class Cards extends Component {
handleEdit = _id => {
this.props.history.push(`/post/edit/${_id}`)
}
render() {
const { _id, title, description } = this.props.post
return (
<div className="card">
<div className="card-content">
<div className="media">
<div className="media-left">
<figure className="image is-48x48">
<img
src="https://bulma.io/images/placeholders/96x96.png"
alt="Placeholder image"
/>
</figure>
</div>
<div className="media-content" style={{ border: "1px grey" }}>
<p className="title is-5">{title}</p>
<p className="content">{description}</p>
<button
onClick={() => {
this.handleEdit(_id)
}}
className="button is-success"
>
Edit
</button>
</div>
</div>
</div>
</div>
)
}
}
const mapStateToProps = state => {
return {
nothing: "nothing"
}
}
export default compose(withRouter, connect(mapStateToProps))(Cards)
updatePost action
export const updatePost = (id, data, redirect) => {
return async dispatch => {
dispatch( { type: "UPDATING_POST_START" })
try {
const res = await axios.put(`http://localhost:3000/api/v1/posts/${id}/edit`, data)
dispatch({
type: "UPDATING_POST_SUCCESS",
data: res.data
})
redirect()
} catch(error) {
dispatch({
type: "UPDATING_POST_FAILURE",
data: { error: "Something went wrong"}
})
}
}
}
I'm not sure if my action is correct or not.
Here's the updatePost controller.
updatePost: async (req, res, next) => {
try {
const data = {
title: req.body.title,
description: req.body.description
}
const post = await Post.findByIdAndUpdate(req.params.id, data, { new: true })
if (!post) {
return res.status(404).json({ message: "No post found "})
}
return res.status(200).json({ post })
} catch(error) {
return next(error)
}
}
One mistake is that to set the current fields you need to use $set in mongodb , also you want to build the object , for example if req.body does not have title it will generate an error
updatePost: async (req, res, next) => {
try {
const data = {};
if(title) data.title=req.body.title;
if(description) data.description=req.body.description
const post = await Post.findByIdAndUpdate(req.params.id, {$set:data}, { new: true })
if (!post) {
return res.status(404).json({ message: "No post found "})
}
return res.status(200).json({ post })
} catch(error) {
return next(error)
}
}

Resources