delete product from database and table (mern project) - javascript

delete product from database and table (mern project)
this is my code. but the product is not being deleted and showing this error - xhr.js:210 DELETE http://localhost:3000/api/v1/admin/product/24e74a20a5e5e8574e231a0 404 (Not Found)
I'm trying but I can't solve the problem. Please give me some advice.
productRoute.js
router.route('/admin/product/:id')
.put(isAuthenticatedUser,authorizeRoles("admin"), updateProduct)
.post(isAuthenticatedUser,authorizeRoles("admin"), deleteProduct)
productController.js
exports.deleteProduct = catchAsyncError(async(req,res,next) => {
const product = await Product.findById(req.params.id)
if(!product){
return next(new ErrorHandler("Product not found",404));
}
await product.remove();
res.status(200).json({
success:true,
message:"product deleted successfully"
})
})
productConstant.js
export const DELETE_PRODUCT_REQUEST = "DELETE_PRODUCT_REQUEST";
export const DELETE_PRODUCT_SUCCESS = "DELETE_PRODUCT_SUCCESS";
export const DELETE_PRODUCT_RESET = "DELETE_PRODUCT_RESET";
export const DELETE_PRODUCT_FAIL = "DELETE_PRODUCT_FAIL";
export const CLEAR_ERROR ="CLEAR_ERROR";
productAction.js
export const deleteProduct = (id) => async (dispatch) => {
try {
dispatch({ type: DELETE_PRODUCT_REQUEST });
const { data } = await axios.delete(`/api/v1/admin/product/${id}`);
dispatch({
type: DELETE_PRODUCT_SUCCESS,
payload: data.success,
});
} catch (error) {
dispatch({
type: DELETE_PRODUCT_FAIL,
payload: error.response.data.message,
});
}
};
productReducer.js
export const productsReducer = (state ={products: []},action) => {
switch(action.type){
case ALL_PRODUCTS_REQUEST:
case ADMIN_PRODUCT_REQUEST:
return{
loading:true,
products:[]
}
case ALL_PRODUCTS_SUCCESS:
return{
loading:false,
products:action.payload.products,
productCount:action.payload.productCount
}
case ADMIN_PRODUCT_SUCCESS:
return{
loading:false,
products:action.payload,
}
case ALL_PRODUCTS_FAIL:
case ADMIN_PRODUCT_FAIL:
return{
loading:false,
error:action.payload
}
case CLEAR_ERROR:
return{
...state,
error:null
}
default:
return state;
}
};
export const productReducer = (state = {}, action) => {
switch (action.type) {
case DELETE_PRODUCT_REQUEST:
return {
...state,
loading: true,
};
case DELETE_PRODUCT_SUCCESS:
return {
...state,
loading: false,
isDeleted: action.payload,
};
case DELETE_PRODUCT_FAIL:
return {
...state,
loading: false,
error: action.payload,
};
case DELETE_PRODUCT_RESET:
return {
...state,
isDeleted: false,
};
case CLEAR_ERROR:
return {
...state,
error: null,
};
default:
return state;
}
};
store
const reducer = combineReducers({
products:productsReducer,
product: productReducer,
})
ProductList.js
import React, { Fragment, useEffect } from 'react'
import { useSelector, useDispatch } from "react-redux";
import SideBar from "./Sidebar";
import {
clearErrors,
getAdminProduct,
deleteProduct
} from "../../Actions/productAction";
import { Link,} from "react-router-dom";
import './ProductList.css'
import { DELETE_PRODUCT_RESET } from "../../Constants/productConstant";
import { useNavigate } from 'react-router';
const ProductList = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const { error, products } = useSelector((state) => state.products);
const { error: deleteError, isDeleted } = useSelector(
(state) => state.product
);
useEffect(() => {
if (error) {
alert(error);
dispatch(clearErrors());
}
if (deleteError) {
alert(deleteError);
dispatch(clearErrors());
}
if (isDeleted) {
alert("Product Deleted Successfully");
navigate("/admin/dashboard");
dispatch({ type: DELETE_PRODUCT_RESET });
}
dispatch(getAdminProduct());
}, [dispatch,error,deleteError,isDeleted]);
return (
<Fragment>
<div className='adminproductlistedit'>
<div className='table_overflow'>
<table id='table'>
<thead> {/* The Head of The Table */}
<tr>
<th className='editTable editProductId'>Product ID</th>
<th className='editTable editName'>Name</th>
<th className='editTable editStock'>Stock</th>
<th className='editTable editCategory'>Category</th>
<th className='editTable editPrice'>Price</th>
<th className='editTable adminActions'>Actions</th>
</tr>
</thead>{/* End of The Head */}
<tbody> {/* The Body of The Table */}
{products &&
products.map((item) => (
<tr className='tr'>
<td>{item._id}</td>
<td>{item.name}</td>
<td>{item.stock}</td>
<td>{item.category}</td>
<td>{item.price}</td>
<td className='actiondiv'>
<button><Link to={`/admin/product/${item._id}`}>
Edit <i className=" editicon fa-solid fa-pencil" />
</Link></button>
<button onClick={() => {
dispatch(deleteProduct(item._id))}}
>Delete <i className="deleteicon fa-solid fa-trash-can" /></button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</Fragment>
)
}
export default ProductList

You should declare your DELETE route as a delete request:
router
.route('/admin/product/:id')
.put(isAuthenticatedUser, authorizeRoles('admin'), updateProduct)
.delete(isAuthenticatedUser, authorizeRoles('admin'), deleteProduct);
Also, you can simplify your controller by using findByIdAndDelete:
exports.deleteProduct = catchAsyncError(async(req,res,next) => {
await Product.findByIdAndDelete(req.params.id)
res.status(200).json({
success:true,
message:"product deleted successfully"
})
})

Related

Troubles Searching term with Redux Api Rest

I'm having problems filtering info consummed by an api. it is actually the nasa api.
What I Want
Look photos by
Rover's Name (input)
by camera name (input)
by date
I successfully completed the last task but the first input is not bringing the image if I look by the rovers name
Search filter
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { getPhotos } from "../../redux/actions/getPhotos";
import { ErrorAlert } from "./Alerts";
import './SecondFinder.css';
export default function SecondFinder() {
const dispatch = useDispatch();
const [term, setSearchTerm] = useState("");
const [alertERR, setAlertERR] = useState(false);
const submitHandler = (e) => {
e.preventDefault();
dispatch(getPhotos(term));
}
return (
<form onSubmit={submitHandler}>
<div className="searchPhotosByRover">
<label>Search by Rovers Name</label>
<input type="text" placeholder="Search by Rover" value={term} onChange={(e) => setSearchTerm(e.target.value)} />
<button className="btn-primary">Search</button>
{alertERR ? <ErrorAlert /> : ""}
</div>
</form>
)
}
Component:
import React from "react";
import { useSelector } from "react-redux";
import { LoadingAlert, PhotoNotFoundAlert } from "./Alerts";
import Photos from "./Photos";
export default function GridPhotos() {
const state = useSelector((state) => state.result);
const renderPhotos = () => {
if (state.loading) {
return <LoadingAlert />;
} if (state.photos.length === 0) {
return <PhotoNotFoundAlert />;
}
return state.photos.map((photo, index) => {
return <Photos key={index} photo={photo} index={index} />;
});
};
return <div className="gridPhotos">{renderPhotos()}</div>;
}
Actions:
import axios from "axios";
export const getPhotos = (date, term) => async (dispatch, getState) => {
dispatch({
type: "FETCH_PHOTOS_REQUEST"
})
try {
const response = await axios.get(`https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?earth_date=${date}&name=${term}&api_key=${process.env.REACT_APP_API_KEY}&page=1`)
dispatch({
type: "FETCH_PHOTOS_SUCCESS",
payload: response.data.photos
})
} catch (error) {
dispatch({
type: "FETCH_PHOTOS_FAILURE",
error
})
}
}
Reducer
const initialState = {
photos: [],
loading: false,
error: null
}
export const getPhotosReducer = (state = initialState, action) => {
console.log("action", action)
switch (action.type) {
case "FETCH_PHOTOS_REQUEST":
return {
...state,
loading: true,
error: null
}
case "FETCH_PHOTOS_SUCCESS":
return {
...state,
loading: false,
photos: action.payload
}
case "FETCH_PHOTOS_FAILURE":
return {
...state,
loading: false,
error: action.error,
photos: []
}
default:
return state
}
}
I just want to look by the rovers name and bring a picture based on this name
enter image description here

Why cannot I invoke action to dispatch?

I am trying to add new functionality in ready social networks to make it possible to edit published posts. But when I invoke getPost and addPostEdited functions from the EditPost react component, I have no result - none of these functions work and its actions do not dispatch. What important operation did I miss?
React component is here:
import React, { Fragment, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import Moment from 'react-moment';
import { connect } from 'react-redux';
import { deletePost, getPost, addPostEdited } from '../../actions/post';
const EditPost = ({
post: { _id, text, name, avatar, user, date }, match
}) => {
useEffect(() => {
getPost(match.params.id);
}, [getPost]);
const [newText, setText] = useState(text);
return (
<Fragment >
<Link to='/posts' className='btn'>
Back To Posts
</Link>
<div>
<Link to={`/profile/${user}`}>
<img className='round-img' src={avatar} alt="" />
<h4>{name}</h4>
</Link>
</div>
<div>
<form
className='form my-1'
onSubmit={e => {
e.preventDefault();
addPostEdited({ text }, _id);
setText('');
}}
>
<textarea
name='text'
cols='30'
rows='5'
placeholder='Edit the post'
value={newText}
onChange={e => setText(e.target.value)}
required
/>
<input type='submit' className='btn btn-dark my-1' value='Publish' />
</form>
<p className='post-date'>
Posted on <Moment format='YYYY/MM/DD'>{date}</Moment>
</p>
<Fragment>
<button
onClick={() => deletePost(_id)}
type='button'
className='btn btn-danger' >
<i className='fas fa-times' />
</button>
</Fragment>
</div>
</Fragment>
);
};
EditPost.propTypes = {
post: PropTypes.object.isRequired,
deletePost: PropTypes.func.isRequired,
getPost: PropTypes.func.isRequired,
addPostEdited: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
post: state.post
});
export default connect(mapStateToProps, { deletePost, getPost, addPostEdited })(EditPost);
File with actions:
import axios from 'axios';
import { setAlert } from './alert';
import {
GET_POSTS,
POST_ERROR,
ADD_POST,
GET_POST,
DELETE_POST,
ADD_COMMENT,
REMOVE_COMMENT,
UPDATE_LIKES,
EDIT_POST,
POST_EDITED
} from './types';
export const getPosts = () => async dispatch => {
try {
const res = await axios.get('api/posts');
dispatch({
type: GET_POSTS,
payload: res.data
});
} catch (err) {
dispatch({
type: POST_ERROR,
payload: { msg: err.response.statusText, status: err.response.status }
});
}
};
export const addPostEdited = (formData, id) => async dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
};
try {
const res = await axios.put(`/api/posts/${id}`, formData, config);
dispatch({
type: POST_EDITED,
payload: res.data
});
dispatch(setAlert('Post Edited', 'success'));
} catch (err) {
dispatch({
type: POST_ERROR,
payload: { msg: err.response.statusText, status: err.response.status }
});
};
};
Reducer:
import {
GET_POSTS,
POST_ERROR,
UPDATE_LIKES,
DELETE_POST,
ADD_POST,
GET_POST,
ADD_COMMENT,
REMOVE_COMMENT,
EDIT_POST,
POST_EDITED
} from '../actions/types';
const initialState = {
posts: [],
post: null,
loading: true,
error: {}
};
export default function(state = initialState, action) {
const { type, payload } = action;
switch (type) {
case GET_POSTS:
return {
...state,
posts: payload,
loading: false,
};
case GET_POST:
case POST_EDITED:
return {
...state,
post: payload,
loading: false,
};
case EDIT_POST:
return {
...state,
post: payload,
loading: false,
};
case ADD_POST:
return {
...state,
posts: [payload, ...state.posts],
loading: false,
};
case DELETE_POST:
return {
...state,
posts: state.posts.filter(post => post._id !== payload),
loading: false
};
case POST_ERROR:
return {
...state,
error: payload,
loading: false
};
case UPDATE_LIKES:
return {
...state,
posts: state.posts.map(post =>
post._id === payload.id ? {...post, likes: payload.likes } : post
),
loading: false
};
case ADD_COMMENT:
return {
...state,
post: {...state.post, comments: payload },
loading: false
};
case REMOVE_COMMENT:
return {
...state,
post: {
...state.post,
comments: state.post.comments.filter(
comment => comment._id !== payload
)
},
loading: false
};
default:
return state;
}
};
You will have to receive deletePost, getPost, addPostEdited from the props.
Currently you are directly using it and not from props which is provided by connect.

React Redux Fetching Data From Api is Null

I am using react and redux to fetch data from an api, but when I try to retrieve the data in my view, I get an error :
TypeError: catData is undefined
I am having a hard time retrieving data from my api in my view, despite the fact that everything is fine on the backened. Any advise on what im doing wrong/ recommendations on how to retrieve data from the reducer will be highly appreciated.
My view looks like this
import React, { useState, useEffect } from "react";
import { connect} from "react-redux";
// #material-ui/core components
import Loader from 'react-loader-spinner'
import { fetchCategories } from "../../../actions/data"
const mapStateToProps = state => {
return {
catData: state.categories
}
}
const mapDispatchToProps = dispatch => {
return {
fetchCategories: () => dispatch(fetchCategories())
}
}
function CategoriesSection({ catData,fetchCategories}) {
useEffect(() => {
fetchCategories();
}, []);
return catData.loading ? (
<div xs={12} sm={10} md={10} lg={10} style={{marginTop: 10}} >
<Loader
type="Puff"
color="red"
height={200}
width={200}
style={{ display: "flex",
justifyContent: "center",
alignItems: "center" }}
/>
</div>
)
: catData.error ? (
<h2> {catData.error} </h2>
): (
<div>
<div className={classes.title} justify="center">
<h2 className={classes.title}>Our Categories</h2>
</div>
<div>
{
catData && catData.cat
}
</div>
</div>
)
}
export default connect(mapStateToProps, mapDispatchToProps)(CategoriesSection)
My reducer looks like this :
import {
CATEGORIES_FETCH_REQUEST,
CATEGORIES_SUCCESS,
CATEGORIES_FAIL
} from "../actions/types";
const initialState = {
loading: false,
categories: [],
businesses: [],
error: ''
}
export default function(state = initialState, action) {
switch(action.type) {
case CATEGORIES_FETCH_REQUEST:
return {
...state,
loading: true
};
case CATEGORIES_SUCCESS:
return {
...state,
loading: false,
categories: action.payload
};
case CATEGORIES_FAIL:
return {
loading: false,
categories: null,
error: action.payload
};
default:
return state;
}
}
And my actions looks like this :
import axios from 'axios';
import {
CATEGORIES_SUCCESS,
CATEGORIES_FAIL,
CATEGORIES_FETCH_REQUEST,
} from "./types";
export const fetchCategories = () => {
return (dispatch) => {
dispatch(fetchCategoryRequest)
axios.get('https://api.xxxxxxx.com/api/v1/categories/')
.then(response => {
const categories = response.data
dispatch(fetchCategorySuccess(categories))
})
.catch(error => {
const err = error.message
dispatch(fetchCategoryFailure(err))
})
}
}
const fetchCategoryRequest = () => {
return {
type: CATEGORIES_FETCH_REQUEST
}
}
const fetchCategorySuccess = categories => {
return {
type: CATEGORIES_SUCCESS,
payload: categories
}
}
const fetchCategoryFailure = err => {
return {
type: CATEGORIES_FAIL,
payload: err
}
}

react js Axios request failed: TypeError: Cannot read property 'token' of undefined?

i have get token from login with react redux, if i am try to authorized it with this token. the error is show Axios request failed: TypeError: Cannot read property 'token' of undefined i want to authorized it with token. the token is stored in localstorage but it can't authorized it when i am using (Token ${props.token} if i am trying this way (Token 5302f4340a76cd80a855286c6d9e0e48d2f519cb} then my AritcleList.js is Authorized it
here is the react-redux authentication
authAction.js
import axios from 'axios';
import * as actionTypes from './actionTypes';
export const authStart = () => {
return {
type: actionTypes.AUTH_START
}
}
export const authSuccess = token => {
return {
type: actionTypes.AUTH_SUCCESS,
token: token
}
}
export const authFail = error => {
return {
type: actionTypes.AUTH_FAIL,
error: error
}
}
export const logout = () => {
localStorage.removeItem('token');
return {
type: actionTypes.AUTH_LOGOUT
};
}
export const authLogin = (userData) => {
return dispatch => {
dispatch(authStart());
axios.post('http://localhost:8000/rest-auth/login/', userData)
.then(res => {
const token = res.data.key;
localStorage.setItem('token', token);
dispatch(authSuccess(token));
})
.catch(err => {
dispatch(authFail(err))
})
}
}
authReducer.js
import * as actionTypes from '../actions/actionTypes';
import { updateObject } from '../utility';
const initialState = {
isAuthenticated: null,
token: null,
error: null,
loading: false
}
const authStart = (state, action) => {
return updateObject(state, {
isAuthenticated: false,
error: null,
loading: true
});
}
const authSuccess = (state, action) => {
return updateObject(state, {
isAuthenticated: true,
token: action.token,
error: null,
loading: false
});
}
const authFail = (state, action) => {
return updateObject(state, {
error: action.error,
loading: false
});
}
const authLogout = (state, action) => {
return updateObject(state, {
token: null
});
}
export default function (state = initialState, action) {
switch (action.type) {
case actionTypes.AUTH_START: return authStart(state, action);
case actionTypes.AUTH_SUCCESS: return authSuccess(state, action);
case actionTypes.AUTH_FAIL: return authFail(state, action);
case actionTypes.AUTH_LOGOUT: return authLogout(state, action);
default:
return state;
}
}
articleList.js
import React, { useState, useEffect } from 'react';
import { Container, Row, Col } from 'react-bootstrap';
import Card from '../components/Card'
import FullPageLoader from "../components/FullPageLoader";
import axios from 'axios';
import { connect } from 'react-redux'
const NewsList = () => {
const [items, setItems] = useState([])
const [isLoading, setLoading] = useState(true)
const [isAuthenticated, setAuth] = useState(true); //i don't know how to authenticate it when i also login
useEffect((props) => {
const fetchItems = async () => {
try {
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Token ${props.token}`
}
}
const res = await axios.get(`${process.env.REACT_APP_API_URL}/api/`, config);
setItems(res.data)
setLoading(false);
}
catch (err) {
console.log(`😱 Axios request failed: ${err}`);
}
}
fetchItems()
})
}, [items]);
return (
<Container className="mt-5">
< div className="bread-header" >
<h5>Dashboard</h5>
</div >
<hr />
<Row>
<Col sm={8}>
{
isLoading ? <FullPageLoader /> :
<div>
{itemData.map((item, index) => (
<Card key={index} item={item} isAuthenticated={isAuthenticated} ></Card>
))}
</div>
}
</Col>
</Row>
</Container >
)
}
const mapStateToProps = (state) => {
return {
isAuthenticated: state.auth.token,
}
}
export default connect(mapStateToProps)(NewsList)
useEffect doesn't take any arguments, so props will always be undefined here:
useEffect((props) => {
I would guess you want to do:
const NewsList = (props) => {
// ...
useEffect(() => {
// ...
}, [items]);
// ...
}
const mapStateToProps = (state) => {
return {
isAuthenticated: !!state.auth.token,
token: state.auth.token
}
}
export default connect(mapStateToProps)(NewsList)

PUT Method in action and reducer in Redux

I have created an UPDATE_ITEM type but how to code it in here I don't have the idea since I want to update it by its ID. Also I want to dipatch this action with the reducer itemReducer.js which I have given in the code below. Can someone please help me with the code?//itemAction.js Action. The get, delete and add routes is working but this put method is giving me headache.
import axios from 'axios';
import { GET_ITEMS, ADD_ITEM, DELETE_ITEM, UPDATE_ITEM, ITEMS_LOADING } from'./types';
export const getItems = () => dispatch => {
dispatch(setItemsLoading());
axios.get('/api/items').then(res =>
dispatch({
type: GET_ITEMS,
payload: res.data
})
);
};
export const addItem = item => dispatch => {
axios.post('/api/items', item).then(res =>
dispatch({
payload: res.data
})
);
};
//UPDATE_ITEM Action Here
export const deleteItem = id => dispatch => {
axios.delete(`/api/items/${id}`).then(res =>
dispatch({
type: DELETE_ITEM,
payload: id
})
);
};
export const setItemsLoading = () => {
return {
type: ITEMS_LOADING
};
};
This is the itemReducer which I also need help
import { GET_ITEMS, DELETE_ITEM, UPDATE_ITEM, ADD_ITEM, ITEMS_LOADING
} from '../actions/types';
const initialState = {
items: [],
loading: false
};
export default function(state = initialState, action) {
switch (action.type) {
case GET_ITEMS:
return {
...state,
items: action.payload,
loading: false
};
case DELETE_ITEM:
return {
...state,
items: state.items.filter(item => item._id !== action.payload)
};
//UPDATE_ITEM Reducer here
case ADD_ITEM:
return {
...state,
items: [action.payload, ...state.items]
};
case ITEMS_LOADING:
return {
...state,
loading: true
};
default:
return state;
}
}
I guess your update looks like the add:
//UPDATE_ITEM Action
export const updateItem = item => dispatch => {
axios.put('/api/items', item).then(res =>
dispatch({
type:'UPDATE_ITEM',
payload: res.data
})
);
};
In your reducer you can use map
case UPDATE_ITEM:
return {
...state,
items: state.items.map(
item =>
item._id === action.payload.id
//return action payload (modified item) instead of
// original item when item id is updated item id
? action.payload
: item//ids not the same, return original item
)
};
import React, { Component } from 'react';
import { Container, ListGroup, ListGroupItem, Button } from 'reactstrap';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import { connect } from 'react-redux';
import { getItems, deleteItem, updateItem } from '../actions/itemActions';
import PropTypes from 'prop-types';
class ShoppingList extends Component {
componentDidMount() {
this.props.getItems();
}
onDeleteClick = id => {
this.props.deleteItem(id);
};
render() {
const { items } = this.props.item;
return (
<Container>
<ListGroup>
<TransitionGroup className="shopping-list">
{items.map(({ _id, name, body }) => (
<CSSTransition key={_id} timeout={500} classNames="fade">
<ListGroupItem>
<Button
className="remove-btn"
color="danger"
size="sm"
onClick={this.onDeleteClick.bind(this, _id)}
>
DELETE
</Button>
{/*An update button will be called here*/}
{/*<Button
className="update-btn"
color="success"
size="sm"
>
Update
</Button>*/}
<div></div>
<table className="rows">
<thead>
<tr>
<td>Name</td>
<td>Body</td>
</tr>
</thead>
<tbody>
<tr>
<td>{ name }</td>
<td>{ body }</td>
</tr>
</tbody>
</table>
</ListGroupItem>
</CSSTransition>
))}
</TransitionGroup>
</ListGroup>
</Container>
);
}
}
ShoppingList.propTypes = {
getItems: PropTypes.func.isRequired,
item: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
item: state.item
});
export default connect(
mapStateToProps,
{ getItems, deleteItem }
)(ShoppingList);

Categories