Skip to content

Commit f3371bb

Browse files
committed
Video-40-Upload-Product-Image
1 parent d84933a commit f3371bb

File tree

7 files changed

+75
-2
lines changed

7 files changed

+75
-2
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ yarn-error.log*
2424
package-lock.json
2525

2626
.env
27+
/uploads/*.jpg

README.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,9 @@
228228
39. Update Product
229229
1. define update api
230230
2. define product update constant, action and reducer
231-
3. use action in Product Edit Screen
231+
3. use action in Product Edit Screen
232+
40. Upload Product Image
233+
1. npm install multer
234+
7. define upload router
235+
8. create uploads folder
236+
9. Handle frontend

backend/routers/uploadRouter.js

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import multer from 'multer';
2+
import express from 'express';
3+
import { isAuth } from '../utils.js';
4+
5+
const uploadRouter = express.Router();
6+
7+
const storage = multer.diskStorage({
8+
destination(req, file, cb) {
9+
cb(null, 'uploads/');
10+
},
11+
filename(req, file, cb) {
12+
cb(null, `${Date.now()}.jpg`);
13+
},
14+
});
15+
16+
const upload = multer({ storage });
17+
18+
uploadRouter.post('/', isAuth, upload.single('image'), (req, res) => {
19+
res.send(`/${req.file.path}`);
20+
});
21+
22+
export default uploadRouter;

backend/server.js

+5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import express from 'express';
22
import mongoose from 'mongoose';
33
import dotenv from 'dotenv';
4+
import path from 'path';
45
import productRouter from './routers/productRouter.js';
56
import userRouter from './routers/userRouter.js';
67
import orderRouter from './routers/orderRouter.js';
8+
import uploadRouter from './routers/uploadRouter.js';
79

810
dotenv.config();
911

@@ -16,12 +18,15 @@ mongoose.connect(process.env.MONGODB_URL || 'mongodb://localhost/amazona', {
1618
useUnifiedTopology: true,
1719
useCreateIndex: true,
1820
});
21+
app.use('/api/uploads', uploadRouter);
1922
app.use('/api/users', userRouter);
2023
app.use('/api/products', productRouter);
2124
app.use('/api/orders', orderRouter);
2225
app.get('/api/config/paypal', (req, res) => {
2326
res.send(process.env.PAYPAL_CLIENT_ID || 'sb');
2427
});
28+
const __dirname = path.resolve();
29+
app.use('/uploads', express.static(path.join(__dirname, '/uploads')));
2530
app.get('/', (req, res) => {
2631
res.send('Server is ready');
2732
});

frontend/src/screens/ProductEditScreen.js

+39
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useEffect, useState } from 'react';
22
import { useDispatch, useSelector } from 'react-redux';
3+
import Axios from 'axios';
34
import { detailsProduct, updateProduct } from '../actions/productActions';
45
import LoadingBox from '../components/LoadingBox';
56
import MessageBox from '../components/MessageBox';
@@ -59,6 +60,31 @@ export default function ProductEditScreen(props) {
5960
})
6061
);
6162
};
63+
const [loadingUpload, setLoadingUpload] = useState(false);
64+
const [errorUpload, setErrorUpload] = useState('');
65+
66+
const userSignin = useSelector((state) => state.userSignin);
67+
const { userInfo } = userSignin;
68+
const uploadFileHandler = async (e) => {
69+
const file = e.target.files[0];
70+
const bodyFormData = new FormData();
71+
bodyFormData.append('image', file);
72+
setLoadingUpload(true);
73+
try {
74+
const { data } = await Axios.post('/api/uploads', bodyFormData, {
75+
headers: {
76+
'Content-Type': 'multipart/form-data',
77+
Authorization: `Bearer ${userInfo.token}`,
78+
},
79+
});
80+
setImage(data);
81+
setLoadingUpload(false);
82+
} catch (error) {
83+
setErrorUpload(error.message);
84+
setLoadingUpload(false);
85+
}
86+
};
87+
6288
return (
6389
<div>
6490
<form className="form" onSubmit={submitHandler}>
@@ -103,6 +129,19 @@ export default function ProductEditScreen(props) {
103129
onChange={(e) => setImage(e.target.value)}
104130
></input>
105131
</div>
132+
<div>
133+
<label htmlFor="imageFile">Image File</label>
134+
<input
135+
type="file"
136+
id="imageFile"
137+
label="Choose Image"
138+
onChange={uploadFileHandler}
139+
></input>
140+
{loadingUpload && <LoadingBox></LoadingBox>}
141+
{errorUpload && (
142+
<MessageBox variant="danger">{errorUpload}</MessageBox>
143+
)}
144+
</div>
106145
<div>
107146
<label htmlFor="category">Category</label>
108147
<input

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"express": "^4.17.1",
2424
"express-async-handler": "^1.1.4",
2525
"jsonwebtoken": "^8.5.1",
26-
"mongoose": "^5.10.7"
26+
"mongoose": "^5.10.7",
27+
"multer": "^1.4.2"
2728
},
2829
"devDependencies": {
2930
"eslint": "^7.9.0",

uploads/file.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)