Skip to content

Commit 7168758

Browse files
authored
Video-34-Create-Product (basir#34)
1 parent dbe0ead commit 7168758

File tree

7 files changed

+120
-15
lines changed

7 files changed

+120
-15
lines changed

README.md

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ JS AMAZONA
7474
5. move index.html, style.css and images to frontend folder
7575
6. rename app.js to index.js
7676
7. update index.html
77-
8. add <script src="main.js"></script> before </body>
77+
8. add script main.js before body tag
7878
9. npm start
7979
10. npm install axios
8080
11. change fetch to axios in HomeScreen
@@ -284,46 +284,69 @@ JS AMAZONA
284284
3. create product function in api.js
285285
4. call create product function in ProductListScreen
286286
5. redirect to edit product
287-
35. Edit Product
287+
35. Edit and Delete Product
288288
1. update parseUrlRequest to get action
289289
2. create ProductEditScreen.js
290290
3. load product data from backend
291291
4. handle form submit
292292
5. save product in backend
293-
36. Delete Product
293+
6. update ProductListScreen.js
294+
7. handle delete button
295+
8. rerender after deletion
296+
36. Upload Product Image
297+
1. npm install multer
298+
2. create routes/uploadRoute.js
299+
3. import express and multer
300+
4. create disk storage with Date.now().jpg as filename
301+
5. set upload as multer({ storage })
302+
6. router.post('/', upload.single('image'))
303+
7. return req.file.path
304+
8. app.use('/api/uploads',uploadRoute) in server.js
305+
9. create uploads folder and put empty file.txt there.
306+
10. ProductEditScreen.js
307+
11. create file input and set id to image-file
308+
12. after_render() handle image-file change
309+
13. create form data
310+
14. call uploadProductImage()
311+
15. create uploadProductImage in api.js
312+
16. update server.js
313+
37. Build Project
314+
1. create build script for frontend
315+
2. create build script for backend
316+
3. update sever.js to serve frontend build folder and uploads folder
317+
4. stop running frontend
318+
5. npm run build
319+
6. check localhost:5000 for running website and showing images
320+
38. Show Categories In Sidebar Menu
294321
1. update ProductListScreen.js
295322
2. handle delete button
296323
3. rerender after deletion
297-
37. Show Categories In Sidebar Menu
298-
1. update ProductListScreen.js
299-
2. handle delete button
300-
3. rerender after deletion
301-
38. Admin Orders
324+
39. Admin Orders
302325
1. create Admin Order menu in header
303326
2. create AdminOrder.js
304327
3. load orders from backend
305328
4. list them in the screen
306329
5. show delete and edit button
307330
6. redirect to order details on edit action
308-
39. Edit Order
331+
40. Edit Order
309332
1. if order is payed show deliver button for admin
310333
2. handle click on deliver button
311334
3. set state to delivered
312-
40. Delete Order
335+
41. Delete Order
313336
1. update OrderListScreen.js
314337
2. handle delete button
315338
3. rerender after deletion
316-
41. Show Summary Report in Dashboard
339+
42. Show Summary Report in Dashboard
317340
1. create summary section
318341
2. style summary
319342
3. create summary backend
320343
4. create getSummary in api.js
321344
5. load data in dashboard screen
322345
6. show 3 boxes for Users, Orders and Sales
323-
42. Show Chart in Dashboard
346+
43. Show Chart in Dashboard
324347
1. import chartist
325348
2. add chartist css to index.html
326349
3. create linear chart for daily sales
327350
4. create pie chart for product categories
328-
43. Publish heroku
351+
44. Publish heroku
329352
1. publish steps

backend/models/productModel.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import mongoose from 'mongoose';
2+
3+
const productSchema = new mongoose.Schema(
4+
{
5+
name: { type: String, required: true },
6+
description: { type: String, required: true },
7+
category: { type: String, required: true },
8+
brand: { type: String, required: true },
9+
image: { type: String, required: true },
10+
price: { type: Number, default: 0.0, required: true },
11+
countInStock: { type: Number, default: 0, required: true },
12+
rating: { type: Number, default: 0.0, required: true },
13+
numReviews: { type: Number, default: 0, required: true },
14+
},
15+
{ timestamps: true }
16+
);
17+
const Product = mongoose.model('Product', productSchema);
18+
export default Product;

backend/routers/productRouter.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import express from 'express';
2+
import expressAysncHandler from 'express-async-handler';
3+
import { isAuth, isAdmin } from '../utils';
4+
import Product from '../models/productModel';
5+
6+
const productRouter = express.Router();
7+
productRouter.post(
8+
'/',
9+
isAuth,
10+
isAdmin,
11+
expressAysncHandler(async (req, res) => {
12+
const product = new Product({
13+
name: 'sample product',
14+
description: 'sample desc',
15+
category: 'sample category',
16+
brand: 'sample brand',
17+
image: '/images/product-1.jpg',
18+
});
19+
const createdProduct = await product.save();
20+
if (createdProduct) {
21+
res
22+
.status(201)
23+
.send({ message: 'Product Created', product: createdProduct });
24+
} else {
25+
res.status(500).send({ message: 'Error in creating product' });
26+
}
27+
})
28+
);
29+
export default productRouter;

backend/server.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import data from './data';
66
import config from './config';
77
import userRouter from './routers/userRouter';
88
import orderRouter from './routers/orderRouter';
9+
import productRouter from './routers/productRouter';
910

1011
mongoose
1112
.connect(config.MONGODB_URL, {
@@ -23,6 +24,7 @@ const app = express();
2324
app.use(cors());
2425
app.use(bodyParser.json());
2526
app.use('/api/users', userRouter);
27+
app.use('/api/products', productRouter);
2628
app.use('/api/orders', orderRouter);
2729
app.get('/api/paypal/clientId', (req, res) => {
2830
res.send({ clientId: config.PAYPAL_CLIENT_ID });

backend/utils.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,10 @@ export const isAuth = (req, res, next) => {
2828
});
2929
}
3030
};
31+
export const isAdmin = (req, res, next) => {
32+
if (req.user && req.user.isAdmin) {
33+
next();
34+
} else {
35+
res.status(401).send({ message: 'Token is not valid for admin user' });
36+
}
37+
};

frontend/src/api.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,25 @@ export const getProduct = async (id) => {
3939
return { error: err.response.data.message || err.message };
4040
}
4141
};
42+
export const createProduct = async () => {
43+
try {
44+
const { token } = getUserInfo();
45+
const response = await axios({
46+
url: `${apiUrl}/api/products`,
47+
method: 'POST',
48+
headers: {
49+
'Content-Type': 'application/json',
50+
Authorization: `Bearer ${token}`,
51+
},
52+
});
53+
if (response.statusText !== 'Created') {
54+
throw new Error(response.data.message);
55+
}
56+
return response.data;
57+
} catch (err) {
58+
return { error: err.response.data.message || err.message };
59+
}
60+
};
4261
export const signin = async ({ email, password }) => {
4362
try {
4463
const response = await axios({

frontend/src/srceens/ProductListScreen.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
import DashboardMenu from '../components/DashboardMenu';
2-
import { getProducts } from '../api';
2+
import { getProducts, createProduct } from '../api';
33

44
const ProductListScreen = {
5-
after_render: () => {},
5+
after_render: () => {
6+
document
7+
.getElementById('create-product-button')
8+
.addEventListener('click', async () => {
9+
const data = await createProduct();
10+
document.location.hash = `/product/${data.product._id}/edit`;
11+
});
12+
},
613
render: async () => {
714
const products = await getProducts();
815
return `

0 commit comments

Comments
 (0)