Skip to content

Commit d84933a

Browse files
authored
Merge pull request #39 from basir/Video-39-Update-Product
Video-39-Update-Product
2 parents 1963f12 + 808e6be commit d84933a

File tree

7 files changed

+108
-9
lines changed

7 files changed

+108
-9
lines changed

README.md

+10-5
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,13 @@
219219
2. build Create Product button
220220
3. define product create constant, action and reducer
221221
4. use action in Product List Screen
222-
5. create edit screen
223-
6. define state
224-
7. create fields
225-
8. load product details
226-
9. add to routes
222+
38. Build Product Edit Screen
223+
1. create edit screen
224+
2. define state
225+
3. create fields
226+
4. load product details
227+
5. add to routes
228+
39. Update Product
229+
1. define update api
230+
2. define product update constant, action and reducer
231+
3. use action in Product Edit Screen

backend/routers/productRouter.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,26 @@ productRouter.post(
5555
res.send({ message: 'Product Created', product: createdProduct });
5656
})
5757
);
58-
58+
productRouter.put(
59+
'/:id',
60+
isAuth,
61+
isAdmin,
62+
expressAsyncHandler(async (req, res) => {
63+
const productId = req.params.id;
64+
const product = await Product.findById(productId);
65+
if (product) {
66+
product.name = req.body.name;
67+
product.price = req.body.price;
68+
product.image = req.body.image;
69+
product.category = req.body.category;
70+
product.brand = req.body.brand;
71+
product.countInStock = req.body.countInStock;
72+
product.description = req.body.description;
73+
const updatedProduct = await product.save();
74+
res.send({ message: 'Product Updated', product: updatedProduct });
75+
} else {
76+
res.status(404).send({ message: 'Product Not Found' });
77+
}
78+
})
79+
);
5980
export default productRouter;

frontend/src/actions/productActions.js

+21
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import {
99
PRODUCT_LIST_FAIL,
1010
PRODUCT_LIST_REQUEST,
1111
PRODUCT_LIST_SUCCESS,
12+
PRODUCT_UPDATE_REQUEST,
13+
PRODUCT_UPDATE_SUCCESS,
14+
PRODUCT_UPDATE_FAIL,
1215
} from '../constants/productConstants';
1316

1417
export const listProducts = () => async (dispatch) => {
@@ -63,3 +66,21 @@ export const createProduct = () => async (dispatch, getState) => {
6366
dispatch({ type: PRODUCT_CREATE_FAIL, payload: message });
6467
}
6568
};
69+
export const updateProduct = (product) => async (dispatch, getState) => {
70+
dispatch({ type: PRODUCT_UPDATE_REQUEST, payload: product });
71+
const {
72+
userSignin: { userInfo },
73+
} = getState();
74+
try {
75+
const { data } = await Axios.put(`/api/products/${product._id}`, product, {
76+
headers: { Authorization: `Bearer ${userInfo.token}` },
77+
});
78+
dispatch({ type: PRODUCT_UPDATE_SUCCESS, payload: data });
79+
} catch (error) {
80+
const message =
81+
error.response && error.response.data.message
82+
? error.response.data.message
83+
: error.message;
84+
dispatch({ type: PRODUCT_UPDATE_FAIL, error: message });
85+
}
86+
};

frontend/src/constants/productConstants.js

+5
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,8 @@ export const PRODUCT_CREATE_REQUEST = 'PRODUCT_CREATE_REQUEST';
1010
export const PRODUCT_CREATE_SUCCESS = 'PRODUCT_CREATE_SUCCESS';
1111
export const PRODUCT_CREATE_FAIL = 'PRODUCT_CREATE_FAIL';
1212
export const PRODUCT_CREATE_RESET = 'PRODUCT_CREATE_RESET';
13+
14+
export const PRODUCT_UPDATE_REQUEST = 'PRODUCT_UPDATE_REQUEST';
15+
export const PRODUCT_UPDATE_SUCCESS = 'PRODUCT_UPDATE_SUCCESS';
16+
export const PRODUCT_UPDATE_FAIL = 'PRODUCT_UPDATE_FAIL';
17+
export const PRODUCT_UPDATE_RESET = 'PRODUCT_UPDATE_RESET';

frontend/src/reducers/productReducers.js

+18
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ const {
99
PRODUCT_CREATE_SUCCESS,
1010
PRODUCT_CREATE_FAIL,
1111
PRODUCT_CREATE_RESET,
12+
PRODUCT_UPDATE_REQUEST,
13+
PRODUCT_UPDATE_SUCCESS,
14+
PRODUCT_UPDATE_FAIL,
15+
PRODUCT_UPDATE_RESET,
1216
} = require('../constants/productConstants');
1317

1418
export const productListReducer = (
@@ -53,3 +57,17 @@ export const productCreateReducer = (state = {}, action) => {
5357
return state;
5458
}
5559
};
60+
export const productUpdateReducer = (state = {}, action) => {
61+
switch (action.type) {
62+
case PRODUCT_UPDATE_REQUEST:
63+
return { loading: true };
64+
case PRODUCT_UPDATE_SUCCESS:
65+
return { loading: false, success: true };
66+
case PRODUCT_UPDATE_FAIL:
67+
return { loading: false, error: action.payload };
68+
case PRODUCT_UPDATE_RESET:
69+
return {};
70+
default:
71+
return state;
72+
}
73+
};

frontend/src/screens/ProductEditScreen.js

+30-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React, { useEffect, useState } from 'react';
22
import { useDispatch, useSelector } from 'react-redux';
3-
import { detailsProduct } from '../actions/productActions';
3+
import { detailsProduct, updateProduct } from '../actions/productActions';
44
import LoadingBox from '../components/LoadingBox';
55
import MessageBox from '../components/MessageBox';
6+
import { PRODUCT_UPDATE_RESET } from '../constants/productConstants';
67

78
export default function ProductEditScreen(props) {
89
const productId = props.match.params.id;
@@ -16,9 +17,21 @@ export default function ProductEditScreen(props) {
1617

1718
const productDetails = useSelector((state) => state.productDetails);
1819
const { loading, error, product } = productDetails;
20+
21+
const productUpdate = useSelector((state) => state.productUpdate);
22+
const {
23+
loading: loadingUpdate,
24+
error: errorUpdate,
25+
success: successUpdate,
26+
} = productUpdate;
27+
1928
const dispatch = useDispatch();
2029
useEffect(() => {
21-
if (!product || product._id !== productId) {
30+
if (successUpdate) {
31+
props.history.push('/productlist');
32+
}
33+
if (!product || product._id !== productId || successUpdate) {
34+
dispatch({ type: PRODUCT_UPDATE_RESET });
2235
dispatch(detailsProduct(productId));
2336
} else {
2437
setName(product.name);
@@ -29,17 +42,31 @@ export default function ProductEditScreen(props) {
2942
setBrand(product.brand);
3043
setDescription(product.description);
3144
}
32-
}, [product, dispatch, productId]);
45+
}, [product, dispatch, productId, successUpdate, props.history]);
3346
const submitHandler = (e) => {
3447
e.preventDefault();
3548
// TODO: dispatch update product
49+
dispatch(
50+
updateProduct({
51+
_id: productId,
52+
name,
53+
price,
54+
image,
55+
category,
56+
brand,
57+
countInStock,
58+
description,
59+
})
60+
);
3661
};
3762
return (
3863
<div>
3964
<form className="form" onSubmit={submitHandler}>
4065
<div>
4166
<h1>Edit Product {productId}</h1>
4267
</div>
68+
{loadingUpdate && <LoadingBox></LoadingBox>}
69+
{errorUpdate && <MessageBox variant="danger">{errorUpdate}</MessageBox>}
4370
{loading ? (
4471
<LoadingBox></LoadingBox>
4572
) : error ? (

frontend/src/store.js

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
productCreateReducer,
1212
productDetailsReducer,
1313
productListReducer,
14+
productUpdateReducer,
1415
} from './reducers/productReducers';
1516
import {
1617
userDetailsReducer,
@@ -48,6 +49,7 @@ const reducer = combineReducers({
4849
userDetails: userDetailsReducer,
4950
userUpdateProfile: userUpdateProfileReducer,
5051
productCreate: productCreateReducer,
52+
productUpdate: productUpdateReducer,
5153
});
5254
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
5355
const store = createStore(

0 commit comments

Comments
 (0)