how to update context state in react - node.js

I am having a problem that when user upload their profile image it did not change, user have to log out and log back in to make a change complete.
Here is my back end how to get image from client and store it on cloudinary:
profilesController.js:
exports.updateAvatar = async (req, res) => {
// Find user with matching token
// const updates = [];
const updateUserAvatar = await models.User.findOne({
where: {
id: req.id,
},
});
// Was user found?
if (updateUserAvatar === null) {
return res.status(200).json({
validationErrors: {
errors: [
{
msg: "Reset is invalid or has expired.",
},
],
},
});
}
// Update user with new info
models.User.update(
{
picture: req.imageUrl,
},
{
where: {
id: updateUserAvatar.dataValues.id,
},
}
);
console.log(updateUserAvatar);
At the console it should gave me a new image url but instead it just keep the old image url
Here is my profilesAPI where my route is:
router.post('/upload/image', function (req, res, next) {
const dUri = new Datauri();
const dataUri = (req) => dUri.format(path.extname(req.name).toString(), req.data);
if (req.files !== undefined && req.files !== null) {
const { file, id } = req.files;
const newFile = dataUri(file).content;
cloudinary.uploader.upload(newFile)
.then(result => {
const imageUrl = result.url;
const data = {id : req.body.id, imageUrl };
updateAvatar(data);
return res.status(200).json({ message: 'Success', data: { imageUrl } });
}).catch(err => res.status(400).json({message:'Error', data: { err}}));
} else {
return res.status(400).json({ message: 'Error' });
}
});
And that's all for my back end code. Here is my front end that cient send image to server:
Here is the method that help user can send image to server:
const UserCard = ({ name, userEmail, isVerified, id, updateUserAvatar, currentUser }) => {
const [selectedValue, setSelectedValue] = useState("a");
const handleChange = (event) => {
setSelectedValue(event.target.value);
};
const [imageSelected, setImageSelected] = useState("");
const uploadImage = () => {
const formData = new FormData();
formData.append("file", imageSelected);
formData.append("id", id);
axios
.post("/api/v1/profiles/upload/image", formData, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((response) => {
updateUserAvatar(response.data.data.imageUrl);
});
};
useEffect(() => {
if (imageSelected !== '') {
uploadImage();
}
}, [imageSelected]);
return (
<div className="avatar--icon_profile">
<Card className="profile--card_container">
<CardContent>
{currentUser.picture ? (
<div>
<input
className="my_file"
type="file"
ref={inputFile}
onChange={(e) => setImageSelected(e.target.files[0])}
/>
<div className="profile-image">
<Avatar
src={currentUser.picture}
alt="Avatar"
className="avatar--profile_image"
onClick={onButtonClick}
/>
</div>
</div>
and here is my Global State. I tried to update nested state in my context but seems like it didn't work.
const GlobalState = (props) => {
// User State -----------------------------------------------------------------------------
const [currentUser, setUser] = useState(props.serverUserData);
console.log(currentUser)
const updateUser = (userData) => {
setUser(userData);
};
// This method is passed through context to update currentUser Avatar
const updateUserAvatar = (picture) => {
setUser({ ...currentUser, picture: picture });
};
const providerValues = {
currentUser,
updateUser,
updateUserAvatar,
};
return (
<GlobalContext.Provider value={providerValues}>
{props.children}
</GlobalContext.Provider>
);
};
export default GlobalState;
and here is my console.log(currentUser) gave me:
{id: "a19cac5c-ea25-4c9c-b1d9-5d6e464869ed", name: "Nhan Nguyen", email: "nhan13574#gmail.com", publicId: "Nh1615314435848", picture: "http://res.cloudinary.com/teammateme/image/upload/v1617229506/gnlooupiekujkrreerxn.png", …}
email: "nhan13574#gmail.com"
id: "a19cac5c-ea25-4c9c-b1d9-5d6e464869ed"
isSessionValid: true
name: "Nhan Nguyen"
picture: "http://res.cloudinary.com/teammateme/image/upload/v1617229506/gnlooupiekujkrreerxn.png"
publicId: "Nh1615314435848"
__proto__: Object
Can anyone help me solve this problem? I really appreciate it
Added GlobalContext.js:
import React from "react";
const globalStateDefaults = {
modals: {
isAuthModalOpen: false,
modalToDisplay: "signup",
toggleModal: () => {},
setModalToDisplay: () => { },
},
user: undefined,
pageName: undefined,
loading: false,
teamProfileId: "",
userProfileId: "",
};
export const GlobalContext = React.createContext(globalStateDefaults);

You need to consume the context where you are trying to update user state.
const {currentUser, updateUser, updateUserAvatar} = React.useContext(GlobalContext)
Then you can call
updateUserAvatar(response.data.data.imageUrl)

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 })
}
})

How to filter posts by category

I tried to filter posts by category but it's not working on frontend
I want when a user clicks on a particular category to get posts in that category
this is my backend (NODEJS)
exports.getMovies = async (req, res) => {
const { pageNo = 0, limit = 10 } = req.query;
// filter category
let filter = {};
if (req.query.categories) {
filter = { category: req.query.categories.split(",") };
}
const movies = await Movie.find(filter)
.populate("category comments")
.sort({ createdAt: -1 })
.skip(parseInt(pageNo) * parseInt(limit))
.limit(parseInt(limit));
const results = movies.map((movie) => ({
id: movie._id,
title: movie.title,
poster: movie.poster?.url,
responsivePosters: movie.poster?.responsive,
category: movie.category,
comments: movie.comments,
genres: movie.genres,
status: movie.status,
}));
res.json({ movies: results });
};
The front end API
export const getMovies = async (pageNo, limit, filter) => {
const token = getToken();
try {
const { data } = await client(
`/movie/movies?pageNo=${pageNo}&limit=${limit}&filter=${filter}`,
{
headers: {
authorization: "Bearer " + token,
"content-type": "multipart/form-data",
},
}
);
return data;
} catch (error) {
return catchError(error);
}
};
The front end CATEGORY COMPONENT
I want the user to filter the post by category by clicking on the category
export default function AllCategory() {
const [allCategories, setAllCategories] = useState([]);
const fetchCategories = async () => {
const res = await getCategoryForUsers();
setAllCategories(res);
};
useEffect(() => {
fetchCategories();
}, []);
return (
<div className=''>
<ul className=' space-x-4 '>
{allCategories.map((c, index) => {
return <li key={index}>{c.title}</li>;
})}
</ul>
</div>
);
}
Remove the ``` as that is not how to post code here.
You'll want to use a filter first in another function
const [selectedCategories, setCurrentlySelectedCategories] = useState([]);
const handleSelectCategory = (category) => {
const currentlySelected = allCategories.filter((item) => item.category == category);
setCurrentlySelectedCategories(currentlySelected);
}
Now just call map on the selectedCategories

How to update data in mongodb database and show in ui

Client-side code...!!!
I want to update the quantity by clicking the Delivered button...
In this section have quantity that i'm show bring database.
const [reload, setReload] = useState(true);
const [stock, setStock] = useState({});
const { _id, quantity } = stock;
useEffect(() => {
const url = `http://localhost:5000/stock/${inventoryId}`;
fetch(url)
.then((res) => res.json())
.then((data) => setStock(data));
}, [reload]);
In this function I want to update quantity that i'm decrising by clicking button
const handleDelivered = () => {
const updateQuantity = parseInt(quantity) - 1; // *actually I want to decrise quantity by clicking Delivered button*
const url = `http://localhost:5000/stock/${inventoryId}`;
fetch(url, {
method: 'PUT',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify(updateQuantity), // *I don't know it's right or wrong and it's so important*
})
.then((res) => res.json())
.then((data) => {
setReload(!reload);
setStock(data);
console.log(data);
});
};
return <button onClick={handleDelivered}>Delivered</button>
Server-side code...!!!
On server-side I want to update just the quantity value...
app.put('/stock/:id', async (req, res) => {
const id = req.params.id;
const updateQuantity = req.body;
const filter = { _id: ObjectId(id) };
const options = { upsert: true };
const updateDoc = {
$set: {
updateQuantity, // *I'm not sure how to set it database. But I want to update quantity value*
},
};
const result = await stockCollection.updateOne(filter, updateDoc, options);
res.send(result);
});
You need to set the updatedQuantity on the "quantity" field of the database. You need to change the "updateDoc" object like this in your server-side code:
const updateDoc = {
$set: {
quantity: updateQuantity,
},
};
Hope this should work.
Client-side code
const handelUpload = (e) => {
e.preventDefault();
const storeQuantity = parseInt(product?.quantity);
const newQuantity = parseInt(e.target.quantity.value);
const quantity = storeQuantity + newQuantity;
if (quantity > 0) {
fetch(`http://localhost:5000/stock/${inventoryId}`, {
method: "PUT",
headers: {
"Content-type": "application/json; charset=UTF-8",
},
body: JSON.stringify({ quantity }),
})
.then((response) => response.json())
.then((data) => {
console.log("success", data);
alert("users added successfully!!!");
e.target.reset();
setIsreload(!isReload);
});
} else {
console.log("input number");
}
};
Server side code api
app.put("/stock/:id", async (req, res) => {
const id = req.params.id;
const updatedProduct = req.body;
console.log(updatedProduct.quantity);
console.log(typeof updatedProduct.quantity);
const filter = { _id: ObjectId(id) };
const options = { upsert: true };
const updatedDoc = {
$set: {
// name: updatedProduct.name,
// email: updatedProduct.email,
quantity: updatedProduct.quantity,
// price: updatedProduct.price,
},
};
const result = await stockCollection.updateOne(filter,updatedDoc,options
);
res.send(result);
});

How do I save uploaded file with other fileds using MERN?

I'm trying to save a uploaded file with other fields like 'title', 'description',.
I'm able to save data using postman but I'm not able to save data from Reacjs form with Redux.
This is how my backend received the data:
const department = req.body.department;
const title = req.body.title;
const description = req.body.description;
const file = req.files.file;
I can save from postman but not react form.
This is my react form:
<form onSubmit={(e) => onSubmit(e)} encType='multipart/form-data'> ... some fields ... </form/
This is my react state and submission form data:
const [file, setFile] = useState('');
const [filename, setFilename] = useState('Choose file...');
const [bodyData, setBodyData] = useState({
title: '',
department: '',
});
const { title, department } = bodyData;
const onChange = (e) =>
setBodyData({ ...bodyData, [e.target.name]: e.target.value });
This is my Redux
// Create document file for specific patient
export const addFile = (form, id) => async (dispatch) => {
console.log(form.bodyData);
try {
const config = {
headers: { 'Content-Type': 'application/json' },
};
const res = await axios.put(
`/api/document/file/${id}`,
(form.bodyData, form.formData),
config
);
dispatch({
type: ADD_DOCUMENT_FILE,
payload: res.data,
});
dispatch(setAlert('Successfully Uploaded Patient Document', 'success'));
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: DOCUMENT_FILE_ERROR,
payload: { msg: err.response.statusText, status: err.response.status },
});
}
};
const onChangeFile = (e) => {
setFile(e.target.files[0]);
setFilename(e.target.files[0].name);
};
const onSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append('file', file);
const collect = { formData, bodyData };
addFile(collect, match.params.id);
};
It seems like you are somewhat confused about how to handle this form submission.
In your onSubmit function, you reference a variable file which isn't defined in that scope, also you return formData, bodyData but bodyData isn't defined, and formData and bodyData are synonyms for the same data, so I don't know why you need both.
Consider this question for an example solution: How to post a file from a form with Axios
Yes. Finally I figured it out.
I changed my submit to this code:
const onSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append('title', title);
formData.append('department', department);
formData.append('file', file);
addFile(formData, match.params.id);
};
and the Redux I changed to this code:
export const addFile = (formData, id) => async (dispatch) => {
// console.log(form.bodyData);
try {
const config = {
// headers: { 'Content-Type': 'multipart/form-data' },
headers: { 'Content-Type': 'application/json' },
};
const res = await axios.put(
`/api/document/file/${id}`,
// { title: form.bodyData.title, department: form.bodyData.department },
formData,
config
);
dispatch({
type: ADD_DOCUMENT_FILE,
payload: res.data,
});
dispatch(setAlert('Successfully Uploaded Patient Document', 'success'));
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: DOCUMENT_FILE_ERROR,
payload: { msg: err.response.statusText, status: err.response.status },
});
}
};

mern - updated values are null in data

I'm trying to update the posts. The PUT request in the back end works fine, returning 200 and updates posts when tested on Postman however when I try to update a post in the front end (react), I'm not receiving any errors but the updated post isn't being updated on submit and the updated fields (title and body) are null. The updated values are null when I console.log(data) in the front end which is why they aren't being sent to the back end but they are shown correctly in post.
Why are the updated values null inside data? How can I update the post with the new values instead of getting null?
data:
post:
Updated code: Frontend
const EditPost = ({match}) => {
const [values, setValues] = useState({
title: "",
body: "",
error: ""
});
const [post, setPost] = useState({});
const { user, token } = isAuthenticated();
const {
title,
body,
error,
} = values;
const init = (id) => {
read(id).then(data => {
if (data.error) {
setValues({...values, error: data.error})
} else {
setValues({...values,
title: data.title,
body: data.body,
})
setPost({title: values.title, body: values.body})
}
})
}
useEffect(() => {
const id = match.params.id;
init(id);
}, []);
useEffect(() => {
setPost({...values });
}, [values.title, values.body]);
const handleChange = (name) => (event) => {
setValues({ ...values, [name]: event.target.value });
};
const clickSubmit = (event) => {
event.preventDefault();
setValues({ ...values, error: "" });
editPost(match.params.userId, match.params.id, token, post).then((data) => {
if (data.error) {
setValues({ ...values, error: data.error });
} else {
setValues({
...values,
title: "",
body: "",
error: false,
});
console.log(post)
console.log(data)
}
});
};
const newPostForm = () => (
<form onSubmit={clickSubmit}>
<div>
<input
onChange={handleChange("title")} type="text"
name="title"
value={title}
/>
</div>
<div className="form-group">
<textarea
onChange={handleChange("body")}
value={body} name="body"
/>
</div>
<button type="submit">Publish</button>
</form>
);
const showError = () => (
<div
style={{ display: error ? "" : "none" }}>
{error}
</div>
);
return (
<div>
{showError()}
{newPostForm()}
</div>
);
};
export default EditPost;
export const editPost = (userId, id, token, post) => {
return fetch(`${API}/${userId}/${id}/edit`, {
method: 'PUT',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${token}`
},
body: JSON.stringify(post)
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
};
postsByUser.js
<Link className="mypost_btn edit_btn" to={`/${_id}/${post._id}/edit`}>
Edit
</Link>
Backend code
exports.edit = (req, res) => {
if (!ObjectID.isValid(req.params.id))
return res.status(400).send(`ID is not valid: ${req.params.id}`)
const {title, body} = req.body
const updatedPost = {title, body }
Post.findByIdAndUpdate(req.params.id, {
$set: updatedPost
}, {new:true}, (error, data) => {
if (error) {
return error
} else {
res.send(data)
console.log(data)
}
})
}
Your problem lies here:
editPost(match.params.userId, match.params.id, token, post)
post is not defined.
Since post is not defined, no data is passed. Hence title and body equal to null. What you will need to do is, assuming from what I'm seeing on your code, is to define a state variable called post. I think you intended to do that:
const [post, setPost] = useState({values.title, values.body});
Then ensure that your post is updated whenever your values change using useEffect(),
useEffect(() => {
setPost({...values });
}, [values.title, value.body]);
So by the time you call your editPost() http-put-method, then post has a value. And it should work.
in EditPost.js editPost(match.params.userId, match.params.id, token).then((data) => { here you are missing the 4th arg which is the "post" it self you send to be updated

Resources