Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 36 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ JS AMAZONA
5. move index.html, style.css and images to frontend folder
6. rename app.js to index.js
7. update index.html
8. add <script src="main.js"></script> before </body>
8. add script main.js before body tag
9. npm start
10. npm install axios
11. change fetch to axios in HomeScreen
Expand Down Expand Up @@ -284,46 +284,69 @@ JS AMAZONA
3. create product function in api.js
4. call create product function in ProductListScreen
5. redirect to edit product
35. Edit Product
35. Edit and Delete Product
1. update parseUrlRequest to get action
2. create ProductEditScreen.js
3. load product data from backend
4. handle form submit
5. save product in backend
36. Delete Product
6. update ProductListScreen.js
7. handle delete button
8. rerender after deletion
36. Upload Product Image
1. npm install multer
2. create routes/uploadRoute.js
3. import express and multer
4. create disk storage with Date.now().jpg as filename
5. set upload as multer({ storage })
6. router.post('/', upload.single('image'))
7. return req.file.path
8. app.use('/api/uploads',uploadRoute) in server.js
9. create uploads folder and put empty file.txt there.
10. ProductEditScreen.js
11. create file input and set id to image-file
12. after_render() handle image-file change
13. create form data
14. call uploadProductImage()
15. create uploadProductImage in api.js
16. update server.js
37. Build Project
1. create build script for frontend
2. create build script for backend
3. update sever.js to serve frontend build folder and uploads folder
4. stop running frontend
5. npm run build
6. check localhost:5000 for running website and showing images
38. Show Categories In Sidebar Menu
1. update ProductListScreen.js
2. handle delete button
3. rerender after deletion
37. Show Categories In Sidebar Menu
1. update ProductListScreen.js
2. handle delete button
3. rerender after deletion
38. Admin Orders
39. Admin Orders
1. create Admin Order menu in header
2. create AdminOrder.js
3. load orders from backend
4. list them in the screen
5. show delete and edit button
6. redirect to order details on edit action
39. Edit Order
40. Edit Order
1. if order is payed show deliver button for admin
2. handle click on deliver button
3. set state to delivered
40. Delete Order
41. Delete Order
1. update OrderListScreen.js
2. handle delete button
3. rerender after deletion
41. Show Summary Report in Dashboard
42. Show Summary Report in Dashboard
1. create summary section
2. style summary
3. create summary backend
4. create getSummary in api.js
5. load data in dashboard screen
6. show 3 boxes for Users, Orders and Sales
42. Show Chart in Dashboard
43. Show Chart in Dashboard
1. import chartist
2. add chartist css to index.html
3. create linear chart for daily sales
4. create pie chart for product categories
43. Publish heroku
44. Publish heroku
1. publish steps
18 changes: 18 additions & 0 deletions backend/models/productModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import mongoose from 'mongoose';

const productSchema = new mongoose.Schema(
{
name: { type: String, required: true },
description: { type: String, required: true },
category: { type: String, required: true },
brand: { type: String, required: true },
image: { type: String, required: true },
price: { type: Number, default: 0.0, required: true },
countInStock: { type: Number, default: 0, required: true },
rating: { type: Number, default: 0.0, required: true },
numReviews: { type: Number, default: 0, required: true },
},
{ timestamps: true }
);
const Product = mongoose.model('Product', productSchema);
export default Product;
29 changes: 29 additions & 0 deletions backend/routers/productRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import express from 'express';
import expressAysncHandler from 'express-async-handler';
import { isAuth, isAdmin } from '../utils';
import Product from '../models/productModel';

const productRouter = express.Router();
productRouter.post(
'/',
isAuth,
isAdmin,
expressAysncHandler(async (req, res) => {
const product = new Product({
name: 'sample product',
description: 'sample desc',
category: 'sample category',
brand: 'sample brand',
image: '/images/product-1.jpg',
});
const createdProduct = await product.save();
if (createdProduct) {
res
.status(201)
.send({ message: 'Product Created', product: createdProduct });
} else {
res.status(500).send({ message: 'Error in creating product' });
}
})
);
export default productRouter;
2 changes: 2 additions & 0 deletions backend/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import data from './data';
import config from './config';
import userRouter from './routers/userRouter';
import orderRouter from './routers/orderRouter';
import productRouter from './routers/productRouter';

mongoose
.connect(config.MONGODB_URL, {
Expand All @@ -23,6 +24,7 @@ const app = express();
app.use(cors());
app.use(bodyParser.json());
app.use('/api/users', userRouter);
app.use('/api/products', productRouter);
app.use('/api/orders', orderRouter);
app.get('/api/paypal/clientId', (req, res) => {
res.send({ clientId: config.PAYPAL_CLIENT_ID });
Expand Down
7 changes: 7 additions & 0 deletions backend/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,10 @@ export const isAuth = (req, res, next) => {
});
}
};
export const isAdmin = (req, res, next) => {
if (req.user && req.user.isAdmin) {
next();
} else {
res.status(401).send({ message: 'Token is not valid for admin user' });
}
};
19 changes: 19 additions & 0 deletions frontend/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,25 @@ export const getProduct = async (id) => {
return { error: err.response.data.message || err.message };
}
};
export const createProduct = async () => {
try {
const { token } = getUserInfo();
const response = await axios({
url: `${apiUrl}/api/products`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
});
if (response.statusText !== 'Created') {
throw new Error(response.data.message);
}
return response.data;
} catch (err) {
return { error: err.response.data.message || err.message };
}
};
export const signin = async ({ email, password }) => {
try {
const response = await axios({
Expand Down
11 changes: 9 additions & 2 deletions frontend/src/srceens/ProductListScreen.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import DashboardMenu from '../components/DashboardMenu';
import { getProducts } from '../api';
import { getProducts, createProduct } from '../api';

const ProductListScreen = {
after_render: () => {},
after_render: () => {
document
.getElementById('create-product-button')
.addEventListener('click', async () => {
const data = await createProduct();
document.location.hash = `/product/${data.product._id}/edit`;
});
},
render: async () => {
const products = await getProducts();
return `
Expand Down