Compare commits
	
		
			No commits in common. 'aws_deployment' and 'develop' have entirely different histories. 
		
	
	
		
			aws_deploy
			...
			develop
		
	
		
	| @ -1,2 +0,0 @@ | |||||||
| /node_modules |  | ||||||
| .env |  | ||||||
| @ -1,131 +0,0 @@ | |||||||
| const Item = require('../models/item') |  | ||||||
| const User = require('../models/user') |  | ||||||
| const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY) |  | ||||||
| const auth = require('../jwt-auth') |  | ||||||
| 
 |  | ||||||
| module.exports.info = (req, res) => { |  | ||||||
| 	let cart = req.body |  | ||||||
| 	let _ids = [] |  | ||||||
| 
 |  | ||||||
| 	for (let i = 0; i < cart.length; i++) { |  | ||||||
| 		_ids.push(cart[i]._id) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	let condition = { '_id': { $in: _ids } } |  | ||||||
| 
 |  | ||||||
| 	Item.find(condition, (err, items) => { |  | ||||||
| 		let cartInfo = [] |  | ||||||
| 
 |  | ||||||
| 		for (let i = 0; i < items.length; i++) { |  | ||||||
| 			cartInfo.push({ |  | ||||||
| 				_id: items[i]._id, |  | ||||||
| 				name: items[i].name, |  | ||||||
| 				quantity: cart[i].quantity, |  | ||||||
| 				unitPrice: items[i].unitPrice |  | ||||||
| 			}) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		res.status(200).json(cartInfo) |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports.checkout = (req, res) => { |  | ||||||
| 	let userId = auth.getId(req.headers.authorization) |  | ||||||
| 	let cart = JSON.parse(req.body.cart) |  | ||||||
| 
 |  | ||||||
| 	let _ids = [] |  | ||||||
| 	let orderItems = [] |  | ||||||
| 	let totalPrice = 0 |  | ||||||
| 
 |  | ||||||
| 	for (let i = 0; i < cart.length; i++) { |  | ||||||
| 		_ids.push(cart[i]._id) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	Item.find({ '_id': { $in: _ids } }, (err, items) => { |  | ||||||
| 		for (let i = 0; i < items.length; i++) { |  | ||||||
| 			for (let j = 0; j < cart.length; j++) { |  | ||||||
| 				if (items[i]._id == cart[j]._id) { |  | ||||||
| 					orderItems.push({ |  | ||||||
| 						_id: items[i]._id, |  | ||||||
| 						name: items[i].name, |  | ||||||
| 						category: items[i].categoryName, |  | ||||||
| 						quantity: cart[j].quantity, |  | ||||||
| 						unitPrice: items[i].unitPrice |  | ||||||
| 					}) |  | ||||||
| 					totalPrice += (cart[j].quantity * items[i].unitPrice) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		User.findOne({ _id: userId }).exec().then((user) => { |  | ||||||
| 			let newOrderDoc = user.orders.create({ |  | ||||||
| 				datetimeRecorded: new Date(), |  | ||||||
| 				paymentMode: 'Cash on Delivery', |  | ||||||
| 				totalPrice: totalPrice, |  | ||||||
| 				items: orderItems |  | ||||||
| 			}) |  | ||||||
| 			user.orders.push(newOrderDoc) |  | ||||||
| 			user.save() |  | ||||||
| 		}) |  | ||||||
| 	}).catch((err) => { |  | ||||||
| 		res.status(400).json({ error: err.message }) |  | ||||||
| 	}) |  | ||||||
| 
 |  | ||||||
| 	res.json({ result: 'success' }) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports.checkoutStripe = (req, res) => { |  | ||||||
| 	let userId = auth.getId(req.headers.authorization) |  | ||||||
| 	let cart = JSON.parse(req.body.cart) |  | ||||||
| 
 |  | ||||||
| 	let _ids = [] |  | ||||||
| 	let orderItems = [] |  | ||||||
| 	let totalPrice = 0 |  | ||||||
| 
 |  | ||||||
| 	for (let i = 0; i < cart.length; i++) { |  | ||||||
| 		console.log(cart[i]) |  | ||||||
| 		_ids.push(cart[i]._id) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	Item.find({ '_id': { $in: _ids } }, (err, items) => { |  | ||||||
| 		for (let i = 0; i < items.length; i++) { |  | ||||||
| 			for (let j = 0; j < cart.length; j++) { |  | ||||||
| 				if (items[i]._id == cart[j]._id) { |  | ||||||
| 					orderItems.push({ |  | ||||||
| 						_id: items[i]._id, |  | ||||||
| 						name: items[i].name, |  | ||||||
| 						category: items[i].categoryName, |  | ||||||
| 						quantity: cart[j].quantity, |  | ||||||
| 						unitPrice: items[i].unitPrice |  | ||||||
| 					}) |  | ||||||
| 					totalPrice += (cart[j].quantity * items[i].unitPrice) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		stripe.charges.create({ |  | ||||||
| 			amount: totalPrice * 100, |  | ||||||
| 			description: null, |  | ||||||
| 			currency: 'php', |  | ||||||
| 			customer: auth.getStripeCustomerId(req.headers.authorization) |  | ||||||
| 		}, (err, charge) => { |  | ||||||
| 			if (err) { return res.status(400).json({ error: err.message }) } |  | ||||||
| 
 |  | ||||||
| 			User.findOne({ _id: userId }).exec().then((user) => { |  | ||||||
| 				let newOrderDoc = user.orders.create({ |  | ||||||
| 					datetimeRecorded: new Date(), |  | ||||||
| 					paymentMode: 'Cash on Delivery', |  | ||||||
| 					stripeChargeId: charge.id, |  | ||||||
| 					totalPrice: totalPrice, |  | ||||||
| 					items: orderItems |  | ||||||
| 				}) |  | ||||||
| 				user.orders.push(newOrderDoc) |  | ||||||
| 				user.save() |  | ||||||
| 			}) |  | ||||||
| 
 |  | ||||||
| 			res.status(200).json({ result: 'success' }) |  | ||||||
| 		}) |  | ||||||
| 	}).catch((err) => { |  | ||||||
| 		res.status(400).json({ error: err.message }) |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| @ -1,9 +0,0 @@ | |||||||
| const Category = require('../models/category') |  | ||||||
| 
 |  | ||||||
| module.exports.all = (req, res) => { |  | ||||||
| 	Category.find().then((categories) => { |  | ||||||
| 		res.status(200).json(categories) |  | ||||||
| 	}).catch(err => { |  | ||||||
| 		res.status(400).json({ error: err.message }) |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| @ -1,49 +0,0 @@ | |||||||
| const Item = require('../models/item') |  | ||||||
| 
 |  | ||||||
| module.exports.all = (req, res) => { |  | ||||||
| 	Item.find({ isArchived: false }).then((items) => { |  | ||||||
| 		res.status(200).json(items) |  | ||||||
| 	}).catch(err => { |  | ||||||
| 		res.status(400).json({ error: err.message }) |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports.detail = (req, res) => { |  | ||||||
| 	let condition = { _id: req.params._id } |  | ||||||
| 
 |  | ||||||
| 	Item.findOne(condition).exec().then((item) => { |  | ||||||
| 		res.status(200).json(item) |  | ||||||
| 	}).catch(err => { |  | ||||||
|         res.status(400).json({ error: err.message }) |  | ||||||
|     }) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports.new = (req, res) => { |  | ||||||
| 	Item.create(req.body).then((item) => { |  | ||||||
| 		res.status(200).json({ result: 'success' }) |  | ||||||
| 	}).catch((err) => { |  | ||||||
| 		res.status(400).json({ error: err.message }) |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports.update = (req, res) => { |  | ||||||
| 	let searchParam = { _id: req.body._id } |  | ||||||
| 	let updateParam = req.body |  | ||||||
| 
 |  | ||||||
| 	Item.findOneAndUpdate(searchParam, updateParam, (item) => { |  | ||||||
| 		res.status(200).json({ result: 'success' }) |  | ||||||
| 	}).catch((err) => {	 |  | ||||||
| 		res.status(400).json({ error: err.message }) |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports.delete = (req, res) => { |  | ||||||
| 	let searchParam = { _id: req.body._id } |  | ||||||
| 	let updateParam = { isArchived: true } |  | ||||||
| 
 |  | ||||||
| 	Item.findOneAndUpdate(searchParam, updateParam, (item) => { |  | ||||||
| 		res.status(200).json({ result: 'success' }) |  | ||||||
| 	}).catch((err) => {	 |  | ||||||
| 		res.status(400).json({ error: err.message }) |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| @ -1,14 +0,0 @@ | |||||||
| const User = require('../models/user') |  | ||||||
| const auth = require('../jwt-auth') |  | ||||||
| 
 |  | ||||||
| module.exports.user = (req, res) => { |  | ||||||
| 	let condition = { |  | ||||||
| 		_id: auth.getId(req.headers.authorization) |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	User.findOne(condition).exec().then((user) => { |  | ||||||
| 		res.status(200).json(user.orders) |  | ||||||
| 	}).catch((err) => { |  | ||||||
| 		res.status(400).json({ error: err.message }) |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| @ -1,54 +0,0 @@ | |||||||
| const User = require('../models/user') |  | ||||||
| const stripe = require('stripe')('sk_test_7UMpcYtFni9koYkpFIruYXmT00EzMN9ci9') |  | ||||||
| const bcrypt = require('bcrypt') |  | ||||||
| const auth = require('../jwt-auth'); |  | ||||||
| 
 |  | ||||||
| module.exports.login = (req, res) => { |  | ||||||
| 	let condition = { email: req.body.email } |  | ||||||
| 
 |  | ||||||
| 	User.findOne(condition).exec().then((user) => { |  | ||||||
|         bcrypt.compare(req.body.password, user.password, (err, result) => { |  | ||||||
|             if (err) { return res.status(400).json({ error: err.message }) } |  | ||||||
| 
 |  | ||||||
|             if (result) { |  | ||||||
|                 return res.status(200).json({ |  | ||||||
|                     result: 'authenticated', |  | ||||||
|                     role: user.role, |  | ||||||
|                     name: user.name, |  | ||||||
|                     token: auth.createToken(user.toObject()) |  | ||||||
|                 }) |  | ||||||
|             } else { |  | ||||||
|                 return res.status(400).json({ error: err.message }) |  | ||||||
|             } |  | ||||||
|         }) |  | ||||||
|     }).catch(err => { |  | ||||||
|         return res.status(400).json({ error: err.message }) |  | ||||||
|     }) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports.register = (req, res) => { |  | ||||||
| 	bcrypt.hash(req.body.password, 10, (err, hash) => { |  | ||||||
| 		// In case encryption encountered an error.
 |  | ||||||
|         if (err) { return res.status(400).json({ error: err.message }) } |  | ||||||
| 
 |  | ||||||
|         stripe.customers.create({ |  | ||||||
|             email: req.body.emailAddress, |  | ||||||
|             source: 'tok_mastercard', |  | ||||||
|         }, (err, customer) => { |  | ||||||
|         	// In case Stripe customer creation failed.
 |  | ||||||
|             if (err) { return res.status(400).json({ error: err.message }) } |  | ||||||
|              |  | ||||||
|             // Provide additional request body information.
 |  | ||||||
|             req.body.password = hash |  | ||||||
|             req.body.stripeCustomerId = customer.id |  | ||||||
|             req.body.role = 'customer' |  | ||||||
| 
 |  | ||||||
|             // Create a new user.
 |  | ||||||
|             User.create(req.body).then((user) => { |  | ||||||
|                 res.status(200).json({ result: 'success' }) |  | ||||||
|             }).catch(err => { |  | ||||||
|                 res.status(400).json({ error: err.message }) |  | ||||||
|             }) |  | ||||||
|         }) |  | ||||||
|     }) |  | ||||||
| } |  | ||||||
| @ -1,50 +0,0 @@ | |||||||
| // Declare dependencies.
 |  | ||||||
| 
 |  | ||||||
| const express = require('express') |  | ||||||
| const bodyParser = require('body-parser') |  | ||||||
| const mongoose = require('mongoose') |  | ||||||
| 
 |  | ||||||
| require('dotenv').config() |  | ||||||
| 
 |  | ||||||
| // Declare constants.
 |  | ||||||
| 
 |  | ||||||
| const app = express() |  | ||||||
| const defaultPort = 4000 |  | ||||||
| const designatedPort = process.env.PORT || defaultPort |  | ||||||
| 
 |  | ||||||
| // Declare middlewares.
 |  | ||||||
| 
 |  | ||||||
| app.use(bodyParser.json()) |  | ||||||
| 
 |  | ||||||
| // Enable the Cross Origin Resource Sharing (CORS).
 |  | ||||||
| 
 |  | ||||||
| app.use(function(req, res, next) { |  | ||||||
| 	res.header('Access-Control-Allow-Origin', '*') |  | ||||||
| 	res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization') |  | ||||||
| 	res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS') |  | ||||||
| 	next() |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| // Declare database connection.
 |  | ||||||
| 
 |  | ||||||
| mongoose.connect(process.env.MONGODB_SRV, {  |  | ||||||
| 	useNewUrlParser:true,  |  | ||||||
| 	useCreateIndex: true, |  | ||||||
| 	useUnifiedTopology: true  |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| mongoose.connection.once('open', () => { |  | ||||||
| 	console.log('Connection to MongoDB Atlas has been successfully tested.') |  | ||||||
| }).catch(function(err) { |  | ||||||
| 	console.log(err) |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| // Declare routes.
 |  | ||||||
| 
 |  | ||||||
| app.use('/api', require('./routes')) |  | ||||||
| 
 |  | ||||||
| // Listen to server requests.
 |  | ||||||
| 
 |  | ||||||
| app.listen(designatedPort, () => { |  | ||||||
| 	console.log('Node.js backend now online in port ' + designatedPort) |  | ||||||
| }) |  | ||||||
| @ -1,44 +0,0 @@ | |||||||
| const jwt = require('jsonwebtoken') |  | ||||||
| const secret = 'MERN-Ecommerce' |  | ||||||
| 
 |  | ||||||
| module.exports.verify = (req, res, next) => { |  | ||||||
|     let header = req.headers.authorization |  | ||||||
|     console.log(req.headers.authorization) |  | ||||||
|      |  | ||||||
|     if (typeof header !== 'undefined') { |  | ||||||
|         req.token = header.slice(7, header.length) |  | ||||||
|          |  | ||||||
|         jwt.verify(req.token, secret, (err, data) => { |  | ||||||
|             (err) ? res.json({ error: 'token-auth-failed' }) : next() |  | ||||||
|         }) |  | ||||||
|     } else { |  | ||||||
|         res.json({ error: 'undefined-auth-header' }) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports.createToken = (user) => { |  | ||||||
|     let data = { |  | ||||||
|         _id: user._id,  |  | ||||||
|         email: user.email,  |  | ||||||
|         role: user.role,  |  | ||||||
|         stripeCustomerId: user.stripeCustomerId |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     return jwt.sign(data, secret, { expiresIn: '2h' }) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports.getId = (authToken) => { |  | ||||||
|     return getPayload(authToken)._id  |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports.getStripeCustomerId = (authToken) => { |  | ||||||
|     return getPayload(authToken).stripeCustomerId  |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| module.exports.getRole = (authToken) => { |  | ||||||
|     return getPayload(authToken).role  |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| getPayload = (authToken) => { |  | ||||||
|     return jwt.decode(authToken.slice(7, authToken.length), {complete: true}).payload |  | ||||||
| } |  | ||||||
| @ -1,12 +0,0 @@ | |||||||
| const mongoose = require('mongoose') |  | ||||||
| const Schema = mongoose.Schema |  | ||||||
| 
 |  | ||||||
| const CategorySchema = new Schema({ |  | ||||||
| 	name: { |  | ||||||
| 		type: String |  | ||||||
| 	} |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| const Category = mongoose.model('category', CategorySchema) |  | ||||||
| 
 |  | ||||||
| module.exports = Category |  | ||||||
| @ -1,32 +0,0 @@ | |||||||
| const mongoose = require('mongoose') |  | ||||||
| const Schema = mongoose.Schema |  | ||||||
| 
 |  | ||||||
| const ItemSchema = new Schema({ |  | ||||||
| 	name: { |  | ||||||
| 		type: String, |  | ||||||
| 		required: [true, 'Item name is required.'] |  | ||||||
| 	}, |  | ||||||
| 	description: { |  | ||||||
| 		type: String, |  | ||||||
| 		required: [true, 'Description is required.'] |  | ||||||
| 	}, |  | ||||||
| 	unitPrice: { |  | ||||||
| 		type: Number, |  | ||||||
| 		required: [true, 'Unit price is required.'] |  | ||||||
| 	}, |  | ||||||
| 	imageLocation: { |  | ||||||
| 		type: String |  | ||||||
| 	}, |  | ||||||
| 	categoryName: { |  | ||||||
| 		type: String, |  | ||||||
| 		required: [true, 'Category name is required.'] |  | ||||||
| 	}, |  | ||||||
| 	isArchived: { |  | ||||||
| 		type: Boolean, |  | ||||||
| 		required: [true, 'Archive status is required.'] |  | ||||||
| 	} |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| const Item = mongoose.model('item', ItemSchema) |  | ||||||
| 
 |  | ||||||
| module.exports = Item |  | ||||||
| @ -1,71 +0,0 @@ | |||||||
| const mongoose = require('mongoose') |  | ||||||
| const Schema = mongoose.Schema |  | ||||||
| 
 |  | ||||||
| const UserSchema = new Schema({ |  | ||||||
|     name: { |  | ||||||
|         type: String, |  | ||||||
|         required: [true, 'Name is required.'] |  | ||||||
|     }, |  | ||||||
|     email: { |  | ||||||
|         type: String, |  | ||||||
|         required: [true, 'Email is required.'] |  | ||||||
|     }, |  | ||||||
|     password: { |  | ||||||
|         type: String, |  | ||||||
|         required: [true, 'Pasword is required.'] |  | ||||||
|     }, |  | ||||||
|     role: { |  | ||||||
|         type: String, |  | ||||||
|         default: 'customer' |  | ||||||
|     }, |  | ||||||
|     stripeCustomerId: { |  | ||||||
|         type: String, |  | ||||||
|         required: [true, 'Stripe customer ID is required.'] |  | ||||||
|     }, |  | ||||||
|     orders: [ |  | ||||||
|         { |  | ||||||
|             datetimeRecorded: { |  | ||||||
|                 type: Date, |  | ||||||
|                 default: new Date() |  | ||||||
|             }, |  | ||||||
|             paymentMode: { |  | ||||||
|                 type: String, |  | ||||||
|                 required: [true, 'Payment mode is required.'] |  | ||||||
|             }, |  | ||||||
|             totalPrice: { |  | ||||||
|                 type: Number, |  | ||||||
|                 required: [true, 'Total price is required.'] |  | ||||||
|             }, |  | ||||||
|             stripeChargeId: { |  | ||||||
|                 type: String, |  | ||||||
|                 default: null |  | ||||||
|             }, |  | ||||||
|             items: [ |  | ||||||
|                 { |  | ||||||
|                     name: { |  | ||||||
|                         type: String, |  | ||||||
|                         required: [true, 'Name is required.'] |  | ||||||
|                     }, |  | ||||||
|                     category: { |  | ||||||
|                         type: String, |  | ||||||
|                         required: [true, 'Category is required.'] |  | ||||||
|                     }, |  | ||||||
|                     quantity: { |  | ||||||
|                         type: Number, |  | ||||||
|                         require: [true, 'Quantity is required.'] |  | ||||||
|                     }, |  | ||||||
|                     unitPrice: { |  | ||||||
|                         type: Number, |  | ||||||
|                         require: [true, 'Unit price is required.'] |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             ] |  | ||||||
|         } |  | ||||||
|     ] |  | ||||||
| }, { |  | ||||||
|     timestamps: true |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| const User = mongoose.model('user', UserSchema) |  | ||||||
| 
 |  | ||||||
| module.exports = User |  | ||||||
| @ -1,26 +0,0 @@ | |||||||
| { |  | ||||||
|   "name": "mern-ecommerce", |  | ||||||
|   "version": "1.0.0", |  | ||||||
|   "description": "", |  | ||||||
|   "main": "index.js", |  | ||||||
|   "scripts": { |  | ||||||
|     "test": "echo \"Error: no test specified\" && exit 1", |  | ||||||
|     "start": "nodemon index.js" |  | ||||||
|   }, |  | ||||||
|   "author": "Sylvan Q. Cahilog", |  | ||||||
|   "license": "ISC", |  | ||||||
|   "dependencies": { |  | ||||||
|     "bcrypt": "^5.0.1", |  | ||||||
|     "body-parser": "^1.19.0", |  | ||||||
|     "cors": "^2.8.5", |  | ||||||
|     "dotenv": "^10.0.0", |  | ||||||
|     "express": "^4.17.1", |  | ||||||
|     "express-session": "^1.16.2", |  | ||||||
|     "jsonwebtoken": "^8.5.1", |  | ||||||
|     "mongoose": "^5.6.1", |  | ||||||
|     "multer": "^1.4.1", |  | ||||||
|     "nodemon": "^1.19.1", |  | ||||||
|     "session-file-store": "^1.3.0", |  | ||||||
|     "stripe": "^7.4.0" |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,32 +0,0 @@ | |||||||
| // Declare constants.
 |  | ||||||
| 
 |  | ||||||
| const express = require('express') |  | ||||||
| const router = express.Router() |  | ||||||
| const auth = require('./jwt-auth') |  | ||||||
| 
 |  | ||||||
| const ItemController = require('./controllers/item') |  | ||||||
| const CategoryController = require('./controllers/category') |  | ||||||
| const UserController = require('./controllers/user') |  | ||||||
| const OrderController = require('./controllers/order') |  | ||||||
| const CartController = require('./controllers/cart') |  | ||||||
| 
 |  | ||||||
| // Route declarations.
 |  | ||||||
| 
 |  | ||||||
| router.get('/items', ItemController.all) |  | ||||||
| router.get('/item/:_id', ItemController.detail) |  | ||||||
| router.post('/item', ItemController.new) |  | ||||||
| router.put('/item', ItemController.update) |  | ||||||
| router.delete('/item', ItemController.delete) |  | ||||||
| 
 |  | ||||||
| router.get('/categories', CategoryController.all) |  | ||||||
| 
 |  | ||||||
| router.get('/orders/user', auth.verify, OrderController.user) |  | ||||||
| 
 |  | ||||||
| router.post('/user/login', UserController.login) |  | ||||||
| router.post('/user/register', UserController.register) |  | ||||||
| 
 |  | ||||||
| router.post('/cart/info', CartController.info) |  | ||||||
| router.post('/cart/checkout', CartController.checkout) |  | ||||||
| router.post('/cart/checkout-stripe', CartController.checkoutStripe) |  | ||||||
| 
 |  | ||||||
| module.exports = router |  | ||||||
| @ -1,24 +0,0 @@ | |||||||
| # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. |  | ||||||
| 
 |  | ||||||
| # dependencies |  | ||||||
| /node_modules |  | ||||||
| /.pnp |  | ||||||
| .pnp.js |  | ||||||
| 
 |  | ||||||
| # testing |  | ||||||
| /coverage |  | ||||||
| 
 |  | ||||||
| # production |  | ||||||
| /build |  | ||||||
| 
 |  | ||||||
| # misc |  | ||||||
| .DS_Store |  | ||||||
| .env |  | ||||||
| .env.local |  | ||||||
| .env.development.local |  | ||||||
| .env.test.local |  | ||||||
| .env.production.local |  | ||||||
| 
 |  | ||||||
| npm-debug.log* |  | ||||||
| yarn-debug.log* |  | ||||||
| yarn-error.log* |  | ||||||
| @ -1,36 +0,0 @@ | |||||||
| { |  | ||||||
|   "name": "frontend", |  | ||||||
|   "version": "0.1.0", |  | ||||||
|   "private": true, |  | ||||||
|   "dependencies": { |  | ||||||
|     "bootstrap": "^4.3.1", |  | ||||||
|     "jquery": "^3.4.1", |  | ||||||
|     "popper.js": "^1.15.0", |  | ||||||
|     "query-string": "^6.8.1", |  | ||||||
|     "react": "^16.8.6", |  | ||||||
|     "react-dom": "^16.8.6", |  | ||||||
|     "react-router-dom": "^5.0.1", |  | ||||||
|     "react-scripts": "3.0.1" |  | ||||||
|   }, |  | ||||||
|   "scripts": { |  | ||||||
|     "start": "react-scripts start", |  | ||||||
|     "build": "react-scripts build", |  | ||||||
|     "test": "react-scripts test", |  | ||||||
|     "eject": "react-scripts eject" |  | ||||||
|   }, |  | ||||||
|   "eslintConfig": { |  | ||||||
|     "extends": "react-app" |  | ||||||
|   }, |  | ||||||
|   "browserslist": { |  | ||||||
|     "production": [ |  | ||||||
|       ">0.2%", |  | ||||||
|       "not dead", |  | ||||||
|       "not op_mini all" |  | ||||||
|     ], |  | ||||||
|     "development": [ |  | ||||||
|       "last 1 chrome version", |  | ||||||
|       "last 1 firefox version", |  | ||||||
|       "last 1 safari version" |  | ||||||
|     ] |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| Before Width: | Height: | Size: 3.8 KiB | 
| @ -1,24 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| 
 |  | ||||||
| <html lang="en"> |  | ||||||
| 
 |  | ||||||
| 	<head> |  | ||||||
| 
 |  | ||||||
| 		<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"/> |  | ||||||
| 
 |  | ||||||
| 		<meta charset="utf-8"/> |  | ||||||
| 		<meta name="viewport" content="width=device-width, initial-scale=1"/> |  | ||||||
| 		<meta name="theme-color" content="#000000"/> |  | ||||||
| 
 |  | ||||||
| 		<title>React App</title> |  | ||||||
| 
 |  | ||||||
| 	</head> |  | ||||||
| 
 |  | ||||||
| 	<body> |  | ||||||
| 
 |  | ||||||
| 		<noscript>You need to enable JavaScript to run this app.</noscript> |  | ||||||
| 		<div id="root" class="pt-5 mb-5 pb-3"></div> |  | ||||||
| 		 |  | ||||||
| 	</body> |  | ||||||
| 
 |  | ||||||
| </html> |  | ||||||
| @ -1,15 +0,0 @@ | |||||||
| { |  | ||||||
|   "short_name": "React App", |  | ||||||
|   "name": "Create React App Sample", |  | ||||||
|   "icons": [ |  | ||||||
|     { |  | ||||||
|       "src": "favicon.ico", |  | ||||||
|       "sizes": "64x64 32x32 24x24 16x16", |  | ||||||
|       "type": "image/x-icon" |  | ||||||
|     } |  | ||||||
|   ], |  | ||||||
|   "start_url": ".", |  | ||||||
|   "display": "standalone", |  | ||||||
|   "theme_color": "#000000", |  | ||||||
|   "background_color": "#ffffff" |  | ||||||
| } |  | ||||||
| @ -1 +0,0 @@ | |||||||
| module.exports.url = process.env.REACT_APP_API_URL |  | ||||||
| @ -1,95 +0,0 @@ | |||||||
| import React, { Component, Fragment } from 'react' |  | ||||||
| import { BrowserRouter, Route, Switch } from 'react-router-dom' |  | ||||||
| import api from '../api-proxy' |  | ||||||
| 
 |  | ||||||
| import Footer from './Footer' |  | ||||||
| import Header from './Header' |  | ||||||
| 
 |  | ||||||
| import Menu from './Menu' |  | ||||||
| import Register from './Register' |  | ||||||
| import Login from './Login' |  | ||||||
| import Logout from './Logout' |  | ||||||
| import ItemCreate from './ItemCreate' |  | ||||||
| import ItemUpdate from './ItemUpdate' |  | ||||||
| import ItemDelete from './ItemDelete' |  | ||||||
| import Cart from './Cart' |  | ||||||
| import Transactions from './Transactions' |  | ||||||
| 
 |  | ||||||
| class App extends Component { |  | ||||||
| 
 |  | ||||||
| 	constructor(props) { |  | ||||||
| 		super(props) |  | ||||||
| 
 |  | ||||||
| 		this.state = { |  | ||||||
| 			name: localStorage.getItem('name'), |  | ||||||
| 			role: localStorage.getItem('role'), |  | ||||||
| 			token: localStorage.getItem('token'), |  | ||||||
| 			cartQuantity: 0 |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	componentDidMount() { |  | ||||||
| 		this.getTotalCartQuantity() |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	setUser() { |  | ||||||
| 		this.setState({ |  | ||||||
| 			name: localStorage.getItem('name'), |  | ||||||
| 			role: localStorage.getItem('role'), |  | ||||||
| 			token: localStorage.getItem('token') |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	unsetUser() { |  | ||||||
| 		localStorage.clear() |  | ||||||
| 
 |  | ||||||
| 		this.setState({ |  | ||||||
| 			name: localStorage.getItem('name'), |  | ||||||
| 			role: localStorage.getItem('role'), |  | ||||||
| 			token: localStorage.getItem('token') |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	getTotalCartQuantity() { |  | ||||||
| 		let cartQuantity = 0 |  | ||||||
|         let cart = JSON.parse(localStorage.getItem('cart')) |  | ||||||
| 
 |  | ||||||
| 		if (cart != null) { |  | ||||||
| 			for (let i = 0; i < cart.length; i++) { |  | ||||||
| 				cartQuantity += parseFloat(cart[i].quantity)  |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		this.setState({ cartQuantity: cartQuantity }) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 	render() { |  | ||||||
| 		let LoginComponent = (props) => (<Login {...props} setUser={ this.setUser.bind(this) }/>) |  | ||||||
| 		let LogoutComponent = (props) => (<Logout {...props} unsetUser={ this.unsetUser.bind(this) }/>) |  | ||||||
| 		let MenuComponent = (props) => (<Menu {...props} getTotalCartQuantity={ this.getTotalCartQuantity.bind(this) }/>) |  | ||||||
| 		let CartComponent = (props) => (<Cart {...props} getTotalCartQuantity={ this.getTotalCartQuantity.bind(this) }/>) |  | ||||||
| 
 |  | ||||||
| 		return ( |  | ||||||
| 			<Fragment> |  | ||||||
| 				<BrowserRouter> |  | ||||||
| 					<Header token={ this.state.token } name={ this.state.name } role={ this.state.role } cartQuantity={ this.state.cartQuantity }/> |  | ||||||
| 					<Switch> |  | ||||||
| 						<Route exact path='/' render={ MenuComponent }/> |  | ||||||
| 						<Route exact path='/register' component={ Register }/> |  | ||||||
| 						<Route exact path='/login' render={ LoginComponent }/> |  | ||||||
| 						<Route exact path='/logout' render={ LogoutComponent }/> |  | ||||||
| 						<Route exact path='/item-create' component={ ItemCreate }/> |  | ||||||
| 						<Route exact path='/item-update' component={ ItemUpdate }/> |  | ||||||
| 						<Route exact path='/item-delete' component={ ItemDelete }/> |  | ||||||
| 						<Route exact path='/cart' render={ CartComponent }/> |  | ||||||
| 						<Route exact path='/transactions' component={ Transactions }/> |  | ||||||
| 					</Switch> |  | ||||||
| 				</BrowserRouter> |  | ||||||
| 				<Footer/> |  | ||||||
| 			</Fragment> |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default App |  | ||||||
| @ -1,239 +0,0 @@ | |||||||
| import React, { Component } from 'react' |  | ||||||
| import { Redirect, Link } from 'react-router-dom' |  | ||||||
| import api from '../api-proxy' |  | ||||||
| 
 |  | ||||||
| document.title = 'Cart' |  | ||||||
| 
 |  | ||||||
| class Cart extends Component { |  | ||||||
| 
 |  | ||||||
| 	constructor(props) { |  | ||||||
| 		super(props) |  | ||||||
| 
 |  | ||||||
| 		this.state = { |  | ||||||
| 			items: [], |  | ||||||
| 			gotoTransactions: false |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	componentWillMount() { |  | ||||||
| 		this.getItems() |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	getItems() { |  | ||||||
| 		let payload = { |  | ||||||
| 			method: 'post', |  | ||||||
| 			headers: { |  | ||||||
| 				'Content-Type': 'application/json' |  | ||||||
| 			}, |  | ||||||
| 			body: localStorage.getItem('cart') |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		fetch(api.url + '/cart/info', payload) |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((cartItems) => { |  | ||||||
| 			console.log(cartItems) |  | ||||||
| 			this.setState({ items: cartItems }) |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	emptyCart() { |  | ||||||
| 		localStorage.removeItem('cart') |  | ||||||
| 		this.props.getTotalCartQuantity() |  | ||||||
| 		this.setState({ items: [] }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	proceedToCheckout() { |  | ||||||
| 		let cart = localStorage.getItem('cart') |  | ||||||
| 
 |  | ||||||
| 		let payload = { |  | ||||||
| 			method: 'post', |  | ||||||
| 			headers: { |  | ||||||
| 				'Content-Type': 'application/json', |  | ||||||
| 				'Authorization': localStorage.getItem('token') |  | ||||||
| 			}, |  | ||||||
| 			body: JSON.stringify({ |  | ||||||
| 				cart: cart |  | ||||||
| 			}) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		fetch(api.url + '/cart/checkout', payload) |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((response) => { |  | ||||||
| 			if (response.result == 'success') { |  | ||||||
| 				this.setState({ gotoTransactions: true }) |  | ||||||
| 				this.emptyCart() |  | ||||||
| 			} else { |  | ||||||
| 				alert(response.error) |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	proceedToStripeCheckout() { |  | ||||||
| 		let cart = localStorage.getItem('cart') |  | ||||||
| 
 |  | ||||||
| 		let payload = { |  | ||||||
| 			method: 'post', |  | ||||||
| 			headers: { |  | ||||||
| 				'Content-Type': 'application/json', |  | ||||||
| 				'Authorization': localStorage.getItem('token') |  | ||||||
| 			}, |  | ||||||
| 			body: JSON.stringify({ |  | ||||||
| 				cart: cart |  | ||||||
| 			}) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		fetch(api.url + '/cart/checkout-stripe', payload) |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((response) => { |  | ||||||
| 			if (response.result == 'success') { |  | ||||||
| 				this.setState({ gotoTransactions: true }) |  | ||||||
| 				this.emptyCart() |  | ||||||
| 			} else { |  | ||||||
| 				alert(response.error) |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	render() { |  | ||||||
| 		if (this.state.gotoTransactions) { |  | ||||||
| 			return <Redirect to='/transactions'/> |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (this.state.items.length == 0) { |  | ||||||
| 			return ( |  | ||||||
| 				<div className="container-fluid mt-3"> |  | ||||||
| 					<h3> No items in cart. </h3> |  | ||||||
| 					<h4> Select a menu item to add to cart from <Link to="/">here</Link>.</h4> |  | ||||||
| 				</div> |  | ||||||
| 			) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		let totalPrice = 0; |  | ||||||
| 
 |  | ||||||
| 		this.state.items.map((item) => { |  | ||||||
| 			totalPrice += (item.quantity * item.unitPrice) |  | ||||||
| 		}) |  | ||||||
| 
 |  | ||||||
| 		return ( |  | ||||||
| 			<div className="container-fluid mt-3"> |  | ||||||
| 
 |  | ||||||
| 				<h3>Cart</h3> |  | ||||||
| 
 |  | ||||||
| 				<table className="table table-bordered"> |  | ||||||
| 
 |  | ||||||
| 					<thead> |  | ||||||
| 
 |  | ||||||
| 						<tr>  |  | ||||||
| 							<th>Item</th> |  | ||||||
| 							<th>Unit Price</th> |  | ||||||
| 							<th>Quantity</th> |  | ||||||
| 							<th>Subtotal</th> |  | ||||||
| 							<th>Action</th> |  | ||||||
| 						</tr> |  | ||||||
| 
 |  | ||||||
| 					</thead> |  | ||||||
| 
 |  | ||||||
| 					<tbody> |  | ||||||
| 
 |  | ||||||
| 						<CartList getItems={ this.getItems.bind(this) } items={ this.state.items } getTotalCartQuantity={ this.props.getTotalCartQuantity }/> |  | ||||||
| 						 |  | ||||||
| 						<tr>  |  | ||||||
| 							<th colSpan="3" className="text-right">Total</th> |  | ||||||
| 							<th className="text-right">₱ { totalPrice.toFixed(2) }</th> |  | ||||||
| 							<th></th> |  | ||||||
| 						</tr> |  | ||||||
| 
 |  | ||||||
| 					</tbody> |  | ||||||
| 
 |  | ||||||
| 				</table> |  | ||||||
| 
 |  | ||||||
| 				<button className="btn btn-danger mr-3" onClick={ this.emptyCart.bind(this) }>Empty Cart</button> |  | ||||||
| 				<button className="btn btn-primary mr-3" onClick={ this.proceedToCheckout.bind(this) }>Proceed to Checkout</button> |  | ||||||
| 				<button className="btn btn-primary" onClick={ this.proceedToStripeCheckout.bind(this) }>Proceed to Checkout (Stripe)</button> |  | ||||||
| 
 |  | ||||||
| 			</div> |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const CartList = (props) => { |  | ||||||
| 	return ( |  | ||||||
| 		props.items.map((item) => { |  | ||||||
| 			return ( |  | ||||||
| 				<tr key={ item._id }> |  | ||||||
| 					<td>{ item.name }</td> |  | ||||||
| 					<td>₱ { (item.unitPrice).toFixed(2) }</td> |  | ||||||
| 					<td> |  | ||||||
| 						<UpdateItemInput getItems={ props.getItems } _id={ item._id } getTotalCartQuantity={ props.getTotalCartQuantity } quantity={ item.quantity }/> |  | ||||||
| 					</td> |  | ||||||
| 					<td className="text-right">₱ { (item.unitPrice * item.quantity).toFixed(2) }</td> |  | ||||||
| 					<td> |  | ||||||
| 						<RemoveItemButton getItems={ props.getItems } _id={ item._id } getTotalCartQuantity={ props.getTotalCartQuantity } /> |  | ||||||
| 					</td> |  | ||||||
| 				</tr> |  | ||||||
| 			) |  | ||||||
| 		}) |  | ||||||
| 	) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const RemoveItemButton = (props) => { |  | ||||||
| 	const removeItem = () => { |  | ||||||
| 		let cart = JSON.parse(localStorage.getItem('cart')) |  | ||||||
| 
 |  | ||||||
| 		for (let i = 0; i < cart.length; i++) { |  | ||||||
| 			if (cart[i]._id == props._id) { |  | ||||||
| 				cart.splice(i) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (cart.length == 0) { |  | ||||||
| 			localStorage.removeItem('cart') |  | ||||||
| 		} else { |  | ||||||
| 			localStorage.setItem('cart', JSON.stringify(cart)) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		props.getTotalCartQuantity() |  | ||||||
| 		props.getItems() |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return ( |  | ||||||
| 		<button onClick={ removeItem } className="btn btn-danger">Remove</button> |  | ||||||
| 	) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class UpdateItemInput extends Component { |  | ||||||
| 
 |  | ||||||
| 	constructor(props) { |  | ||||||
| 		super(props)  |  | ||||||
| 
 |  | ||||||
| 		this.state = { |  | ||||||
| 			quantity: props.quantity |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	updateQuantity(e) { |  | ||||||
| 		let cart = JSON.parse(localStorage.getItem('cart')) |  | ||||||
| 
 |  | ||||||
| 		for (let i = 0; i < cart.length; i++) { |  | ||||||
| 			if (cart[i]._id == this.props._id) { |  | ||||||
| 				cart[i].quantity = parseFloat(e.target.value) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		localStorage.setItem('cart', JSON.stringify(cart)) |  | ||||||
| 		 |  | ||||||
| 		this.setState({ quantity: e.target.value }) |  | ||||||
| 		this.props.getTotalCartQuantity() |  | ||||||
|         this.props.getItems() |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	render() { |  | ||||||
| 		return ( |  | ||||||
| 			<input value={ this.state.quantity } onChange={ this.updateQuantity.bind(this) } type="number" className="form-control" min="1"/> |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default Cart |  | ||||||
| @ -1,13 +0,0 @@ | |||||||
| import React from 'react' |  | ||||||
| 
 |  | ||||||
| const Footer = () => { |  | ||||||
| 	return ( |  | ||||||
| 		<footer className="bg-dark fixed-bottom"> |  | ||||||
| 			<p className="text-center py-2 text-white my-0"> |  | ||||||
| 				Copyright © 2019 Zuitt Bootcampers |  | ||||||
| 			</p> |  | ||||||
| 		</footer> |  | ||||||
| 	) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default Footer |  | ||||||
| @ -1,68 +0,0 @@ | |||||||
| import React from 'react' |  | ||||||
| import { Link } from 'react-router-dom' |  | ||||||
| 
 |  | ||||||
| const Header = (props) => { |  | ||||||
| 	let navRight = (props.token === null) ? |  | ||||||
| 		( |  | ||||||
| 			<React.Fragment> |  | ||||||
| 				<li className="nav-item"> |  | ||||||
| 					<Link className="nav-link" to="/login">Login</Link> |  | ||||||
| 				</li> |  | ||||||
| 
 |  | ||||||
| 				<li className="nav-item"> |  | ||||||
| 					<Link className="nav-link" to="/register">Register</Link> |  | ||||||
| 				</li> |  | ||||||
| 			</React.Fragment> |  | ||||||
| 		) : |  | ||||||
| 		( |  | ||||||
| 			<React.Fragment> |  | ||||||
| 				<li className="nav-item"> |  | ||||||
| 					<Link className="nav-link" to="/">{ props.name }</Link> |  | ||||||
| 				</li> |  | ||||||
| 
 |  | ||||||
| 				<li className="nav-item"> |  | ||||||
| 					<Link className="nav-link" to="/transactions">Transactions</Link> |  | ||||||
| 				</li> |  | ||||||
| 
 |  | ||||||
| 				<li className="nav-item"> |  | ||||||
| 					<Link className="nav-link" to="/logout">Logout</Link> |  | ||||||
| 				</li> |  | ||||||
| 			</React.Fragment> |  | ||||||
| 		) |  | ||||||
| 
 |  | ||||||
| 	return ( |  | ||||||
| 		<nav className="navbar navbar-expand-lg navbar-dark bg-dark fixed-top"> |  | ||||||
| 
 |  | ||||||
| 			<Link className="navbar-brand" to="/">MERN E-Commerce</Link> |  | ||||||
| 
 |  | ||||||
| 			<button className="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbar"> |  | ||||||
| 				<span className="navbar-toggler-icon"></span> |  | ||||||
| 			</button> |  | ||||||
| 
 |  | ||||||
| 			<div className="collapse navbar-collapse" id="navbar"> |  | ||||||
| 
 |  | ||||||
| 				<ul className="navbar-nav mr-auto"> |  | ||||||
| 
 |  | ||||||
| 					<li className="nav-item"> |  | ||||||
| 						<Link className="nav-link" to="/">Menu</Link> |  | ||||||
| 					</li> |  | ||||||
| 
 |  | ||||||
| 					<li className="nav-item"> |  | ||||||
| 						<Link className="nav-link" to="/cart">Cart <span className="badge badge-light">{ props.cartQuantity }</span></Link> |  | ||||||
| 					</li> |  | ||||||
| 
 |  | ||||||
| 				</ul> |  | ||||||
| 
 |  | ||||||
| 				<ul className="navbar-nav ml-auto"> |  | ||||||
| 
 |  | ||||||
| 					{ navRight } |  | ||||||
| 
 |  | ||||||
| 				</ul> |  | ||||||
| 
 |  | ||||||
| 			</div> |  | ||||||
| 
 |  | ||||||
| 		</nav> |  | ||||||
| 	) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default Header |  | ||||||
| @ -1,152 +0,0 @@ | |||||||
| import React, { Component, Fragment } from 'react' |  | ||||||
| import { Redirect } from 'react-router-dom' |  | ||||||
| import api from '../api-proxy' |  | ||||||
| 
 |  | ||||||
| document.title = 'Create Item' |  | ||||||
| 
 |  | ||||||
| const ItemCreate = () => ( |  | ||||||
| 	<div className="container-fluid mt-3"> |  | ||||||
| 
 |  | ||||||
| 		<div className="row"> |  | ||||||
| 
 |  | ||||||
| 			<div className="col-6 mx-auto"> |  | ||||||
| 
 |  | ||||||
| 				<h3 className="text-center">Add Item</h3> |  | ||||||
| 
 |  | ||||||
| 				<div className="card"> |  | ||||||
| 
 |  | ||||||
| 					<div className="card-header">Item Information</div> |  | ||||||
| 
 |  | ||||||
| 					<div className="card-body"> |  | ||||||
| 
 |  | ||||||
| 						<ItemCreateForm/> |  | ||||||
| 
 |  | ||||||
| 					</div> |  | ||||||
| 
 |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 			</div> |  | ||||||
| 
 |  | ||||||
| 		</div> |  | ||||||
| 
 |  | ||||||
| 	</div> |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| class ItemCreateForm extends Component { |  | ||||||
| 
 |  | ||||||
| 	constructor(props) { |  | ||||||
| 		super(props) |  | ||||||
| 
 |  | ||||||
| 		this.fileInput = React.createRef() |  | ||||||
| 
 |  | ||||||
| 		this.state = { |  | ||||||
| 			itemName: '', |  | ||||||
| 			description: '', |  | ||||||
| 			unitPrice: '', |  | ||||||
| 			categoryName: undefined, |  | ||||||
| 			categories: [], |  | ||||||
| 			returnToMenu: false |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	componentWillMount() { |  | ||||||
| 		fetch(api.url + '/categories') |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((categories) => { |  | ||||||
| 			this.setState({ categories: categories })		 |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	itemNameChangeHandler(e) { |  | ||||||
| 		this.setState({ itemName: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	descriptionChangeHandler(e) { |  | ||||||
| 		this.setState({ description: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	unitPriceChangeHandler(e) { |  | ||||||
| 		this.setState({ unitPrice: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	categoryNameChangeHandler(e) { |  | ||||||
| 		this.setState({ categoryName: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	formSubmitHandler(e) { |  | ||||||
| 		e.preventDefault() |  | ||||||
| 
 |  | ||||||
| 		let payload = { |  | ||||||
| 			method: 'post', |  | ||||||
| 			headers: { |  | ||||||
| 				'Content-Type': 'application/json' |  | ||||||
| 			}, |  | ||||||
| 			body: JSON.stringify({ |  | ||||||
| 				name: this.state.itemName, |  | ||||||
| 				description: this.state.description, |  | ||||||
| 				unitPrice: this.state.unitPrice, |  | ||||||
| 				categoryName: this.state.categoryName, |  | ||||||
| 				isArchived: 0 |  | ||||||
| 			}) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		fetch(api.url + '/item', payload) |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((response) => { |  | ||||||
| 			if (response.error != null) { |  | ||||||
| 				alert(response.error) |  | ||||||
| 			} else { |  | ||||||
| 				this.setState({ returnToMenu: true }) |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	render() { |  | ||||||
| 		if (this.state.returnToMenu) { |  | ||||||
| 			return <Redirect to='/'/> |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return ( |  | ||||||
| 			<form onSubmit={ this.formSubmitHandler.bind(this) }> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Item Name</label> |  | ||||||
| 					<input value={ this.state.itemName } onChange={ this.itemNameChangeHandler.bind(this) } type="text" className="form-control" required/> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Description</label> |  | ||||||
| 					<input value={ this.state.description } onChange={ this.descriptionChangeHandler.bind(this) } type="text" className="form-control"/> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Unit Price</label> |  | ||||||
| 					<input value={ this.state.unitPrice } onChange={ this.unitPriceChangeHandler.bind(this) } type="number" className="form-control" required/> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Category</label> |  | ||||||
| 					<select value={ this.state.categoryName } onChange={ this.categoryNameChangeHandler.bind(this) } className="form-control" > |  | ||||||
| 						<option value selected disabled>Select Category</option> |  | ||||||
| 						{ |  | ||||||
| 							this.state.categories.map((category) => { |  | ||||||
| 								return <option key={ category._id } value={ category.name }>{ category.name }</option> |  | ||||||
| 							}) |  | ||||||
| 						} |  | ||||||
| 					</select> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Image</label> |  | ||||||
| 					<input type="file" className="form-control" ref={ this.fileInput }/> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<button type="submit" className="btn btn-success btn-block">Add</button> |  | ||||||
| 
 |  | ||||||
| 			</form> |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default ItemCreate |  | ||||||
| @ -1,140 +0,0 @@ | |||||||
| import React, { Component } from 'react' |  | ||||||
| import queryString from 'query-string' |  | ||||||
| import { Redirect, Link } from 'react-router-dom' |  | ||||||
| import api from '../api-proxy' |  | ||||||
| 
 |  | ||||||
| document.title = 'Delete Item' |  | ||||||
| 
 |  | ||||||
| const ItemDelete = (props) => ( |  | ||||||
| 	<div className="container-fluid mt-3"> |  | ||||||
| 
 |  | ||||||
|         <div className="row"> |  | ||||||
| 
 |  | ||||||
|             <div className="col-6 mx-auto"> |  | ||||||
| 
 |  | ||||||
|                 <h3 className="text-center">Delete Item</h3> |  | ||||||
| 
 |  | ||||||
|                 <div className="card"> |  | ||||||
| 
 |  | ||||||
|                     <div className="card-header">Item Information</div> |  | ||||||
| 
 |  | ||||||
|                     <div className="card-body"> |  | ||||||
| 
 |  | ||||||
|                     	<ItemDeleteForm urlParam={ props.location.search } /> |  | ||||||
| 
 |  | ||||||
|                     </div> |  | ||||||
| 
 |  | ||||||
|                 </div> |  | ||||||
| 
 |  | ||||||
|             </div> |  | ||||||
| 
 |  | ||||||
|         </div> |  | ||||||
| 
 |  | ||||||
|     </div> |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| class ItemDeleteForm extends Component { |  | ||||||
| 
 |  | ||||||
| 	constructor(props) { |  | ||||||
| 		super(props) |  | ||||||
| 
 |  | ||||||
| 		let params = queryString.parse(this.props.urlParam) |  | ||||||
| 
 |  | ||||||
| 		this.state = { |  | ||||||
| 			_id: params._id, |  | ||||||
| 			itemName: '', |  | ||||||
| 			description: '', |  | ||||||
| 			unitPrice: '', |  | ||||||
| 			categoryName: undefined, |  | ||||||
| 			categories: [], |  | ||||||
| 			returnToMenu: false |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	componentWillMount() { |  | ||||||
| 		fetch(api.url + '/categories') |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((categories) => { |  | ||||||
| 			this.setState({ categories: categories })	 |  | ||||||
| 
 |  | ||||||
| 			fetch(api.url + '/item/' + this.state._id) |  | ||||||
| 			.then((response) => response.json()) |  | ||||||
| 			.then((item) => { |  | ||||||
| 				this.setState({  |  | ||||||
| 					itemName: item.name, |  | ||||||
| 					description: item.description, |  | ||||||
| 					unitPrice: item.unitPrice, |  | ||||||
| 					categoryName: item.categoryName |  | ||||||
| 				}) |  | ||||||
| 			}) |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	formSubmitHandler(e) { |  | ||||||
| 		e.preventDefault() |  | ||||||
| 
 |  | ||||||
| 		let payload = { |  | ||||||
| 			method: 'delete', |  | ||||||
| 			headers: { |  | ||||||
| 				'Content-Type': 'application/json' |  | ||||||
| 			}, |  | ||||||
| 			body: JSON.stringify({ |  | ||||||
| 				'_id': this.state._id |  | ||||||
| 			}) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		fetch(api.url + '/item', payload) |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((response) => { |  | ||||||
| 			if (response.error != null) { |  | ||||||
| 				alert(response.error) |  | ||||||
| 			} else { |  | ||||||
| 				this.setState({ returnToMenu: true }) |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	render() { |  | ||||||
| 		if (this.state.returnToMenu) { |  | ||||||
| 			return <Redirect to='/'/> |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return ( |  | ||||||
| 			<form onSubmit={ this.formSubmitHandler.bind(this) }> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Item Name</label> |  | ||||||
| 					<input value={ this.state.itemName } type="text" className="form-control" readOnly/> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Description</label> |  | ||||||
| 					<input value={ this.state.description } type="text" className="form-control" readOnly/> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Unit Price</label> |  | ||||||
| 					<input value={ this.state.unitPrice } type="number" className="form-control"  readOnly/> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Category</label> |  | ||||||
| 					<select value={ this.state.categoryName } className="form-control" readOnly > |  | ||||||
| 						<option value disabled>Select Category</option> |  | ||||||
| 						{ |  | ||||||
| 							this.state.categories.map((category) => { |  | ||||||
| 								return <option key={ category.id } value= { category.name }>{ category.name }</option> |  | ||||||
| 							}) |  | ||||||
| 						} |  | ||||||
| 					</select> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<button type="submit" className="btn btn-danger btn-block">Delete</button> |  | ||||||
| 				<Link className="btn btn-warning btn-block" to="/">Cancel</Link> |  | ||||||
| 
 |  | ||||||
| 			</form> |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default ItemDelete |  | ||||||
| @ -1,169 +0,0 @@ | |||||||
| import React, { Component } from 'react' |  | ||||||
| import queryString from 'query-string' |  | ||||||
| import { Redirect, Link } from 'react-router-dom' |  | ||||||
| import api from '../api-proxy' |  | ||||||
| 
 |  | ||||||
| document.title = 'Update Item' |  | ||||||
| 
 |  | ||||||
| const ItemUpdate = (props) => ( |  | ||||||
| 	<div className="container-fluid mt-3"> |  | ||||||
| 
 |  | ||||||
|         <div className="row"> |  | ||||||
| 
 |  | ||||||
|             <div className="col-6 mx-auto"> |  | ||||||
| 
 |  | ||||||
|                 <h3 className="text-center">Update Item</h3> |  | ||||||
| 
 |  | ||||||
|                 <div className="card"> |  | ||||||
| 
 |  | ||||||
|                     <div className="card-header">Item Information</div> |  | ||||||
| 
 |  | ||||||
|                     <div className="card-body"> |  | ||||||
| 
 |  | ||||||
| 						<ItemUpdateForm urlParam={ props.location.search }/> |  | ||||||
| 
 |  | ||||||
|                     </div> |  | ||||||
| 
 |  | ||||||
|                 </div> |  | ||||||
| 
 |  | ||||||
|             </div> |  | ||||||
| 
 |  | ||||||
|         </div> |  | ||||||
| 
 |  | ||||||
|     </div> |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| class ItemUpdateForm extends Component { |  | ||||||
| 
 |  | ||||||
| 	constructor(props) { |  | ||||||
| 		super(props) |  | ||||||
| 
 |  | ||||||
| 		this.fileInput = React.createRef() |  | ||||||
| 		let params = queryString.parse(this.props.urlParam) |  | ||||||
| 
 |  | ||||||
| 		this.state = { |  | ||||||
| 			_id: params._id, |  | ||||||
| 			itemName: '', |  | ||||||
| 			description: '', |  | ||||||
| 			unitPrice: '', |  | ||||||
| 			categoryName: undefined, |  | ||||||
| 			categories: [], |  | ||||||
| 			returnToMenu: false |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	componentWillMount() { |  | ||||||
| 		fetch(api.url + '/categories') |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((categories) => { |  | ||||||
| 			this.setState({ categories: categories }) |  | ||||||
| 
 |  | ||||||
| 			fetch(api.url + '/item/' + this.state._id) |  | ||||||
| 			.then((response) => response.json()) |  | ||||||
| 			.then((item) => { |  | ||||||
| 				this.setState({  |  | ||||||
| 					itemName: item.name, |  | ||||||
| 					description: item.description, |  | ||||||
| 					unitPrice: item.unitPrice, |  | ||||||
| 					categoryName: item.categoryName |  | ||||||
| 				}) |  | ||||||
| 			})		 |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	itemNameChangeHandler(e) { |  | ||||||
| 		this.setState({ itemName: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	descriptionChangeHandler(e) { |  | ||||||
| 		this.setState({ description: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	unitPriceChangeHandler(e) { |  | ||||||
| 		this.setState({ unitPrice: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	categoryNameChangeHandler(e) { |  | ||||||
| 		this.setState({ categoryName: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	formSubmitHandler(e) { |  | ||||||
| 		e.preventDefault() |  | ||||||
| 
 |  | ||||||
| 		let payload = { |  | ||||||
| 			method: 'put', |  | ||||||
| 			headers: { |  | ||||||
| 				'Content-Type': 'application/json' |  | ||||||
| 			}, |  | ||||||
| 			body: JSON.stringify({ |  | ||||||
| 				_id: this.state._id, |  | ||||||
| 				name: this.state.itemName, |  | ||||||
| 				description: this.state.description, |  | ||||||
| 				unitPrice: this.state.unitPrice, |  | ||||||
| 				categoryName: this.state.categoryName, |  | ||||||
| 				isArchived: 0 |  | ||||||
| 			}) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		fetch(api.url + '/item', payload) |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((response) => { |  | ||||||
| 			if (response.error != null) { |  | ||||||
| 				alert(response.error) |  | ||||||
| 			} else { |  | ||||||
| 				this.setState({ returnToMenu: true }) |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	render() { |  | ||||||
| 		if (this.state.returnToMenu) { |  | ||||||
| 			return <Redirect to='/'/> |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return ( |  | ||||||
| 			<form onSubmit={ this.formSubmitHandler.bind(this) }> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Item Name</label> |  | ||||||
| 					<input value={ this.state.itemName } onChange={ this.itemNameChangeHandler.bind(this) } type="text" className="form-control" required/> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Description</label> |  | ||||||
| 					<input value={ this.state.description } onChange={ this.descriptionChangeHandler.bind(this) } type="text" className="form-control"/> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Unit Price</label> |  | ||||||
| 					<input value={ this.state.unitPrice } onChange={ this.unitPriceChangeHandler.bind(this) } type="number" className="form-control" required/> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Category</label> |  | ||||||
| 					<select value={ this.state.categoryName } onChange={ this.categoryNameChangeHandler.bind(this) } className="form-control" > |  | ||||||
| 						<option value disabled>Select Category</option> |  | ||||||
| 						{ |  | ||||||
| 							this.state.categories.map((category) => { |  | ||||||
| 								return <option key={ category._id } value= { category.name }>{ category.name }</option> |  | ||||||
| 							}) |  | ||||||
| 						} |  | ||||||
| 					</select> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group"> |  | ||||||
| 					<label>Image</label> |  | ||||||
| 					<input type="file" className="form-control" ref={ this.fileInput } /> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<button type="submit" className="btn btn-success btn-block">Update</button> |  | ||||||
| 				<Link className="btn btn-warning btn-block" to="/">Cancel</Link> |  | ||||||
| 
 |  | ||||||
| 			</form> |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default ItemUpdate |  | ||||||
| @ -1,134 +0,0 @@ | |||||||
| import React, { Component } from 'react' |  | ||||||
| import queryString from 'query-string' |  | ||||||
| import { Redirect } from 'react-router-dom' |  | ||||||
| import api from '../api-proxy' |  | ||||||
| 
 |  | ||||||
| document.title = 'Login' |  | ||||||
| 
 |  | ||||||
| const Login = (props) => { |  | ||||||
| 	if (localStorage.getItem('token') != null) { |  | ||||||
| 		return <Redirect to='/'/> |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return ( |  | ||||||
| 		<div className="container-fluid mt-3"> |  | ||||||
| 
 |  | ||||||
| 			<div className="row"> |  | ||||||
| 
 |  | ||||||
| 				<div className="col-6 mx-auto"> |  | ||||||
| 
 |  | ||||||
| 					<h3 className="text-center">Login</h3> |  | ||||||
| 
 |  | ||||||
| 					<div className="card"> |  | ||||||
| 					 |  | ||||||
| 						<div className="card-header">Enter Login Information</div> |  | ||||||
| 
 |  | ||||||
| 						<div className="card-body"> |  | ||||||
| 
 |  | ||||||
| 							<LoginForm urlParam={ props.location.search } setUser={ props.setUser }/>	 |  | ||||||
| 							 |  | ||||||
| 						</div> |  | ||||||
| 
 |  | ||||||
| 					</div> |  | ||||||
| 
 |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 			</div> |  | ||||||
| 		 |  | ||||||
| 		</div> |  | ||||||
| 	) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class LoginForm extends Component { |  | ||||||
| 
 |  | ||||||
| 	constructor(props) { |  | ||||||
| 		super(props) |  | ||||||
| 
 |  | ||||||
| 		this.state = { |  | ||||||
| 			email:'', |  | ||||||
| 			password:'', |  | ||||||
| 			errorMessage:'', |  | ||||||
| 			gotoMenu: false |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	emailChangeHandler(e) { |  | ||||||
| 		this.setState({ email: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	passwordChangeHandler(e) { |  | ||||||
| 		this.setState({ password: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	formSubmitHandler(e) { |  | ||||||
| 		e.preventDefault() |  | ||||||
| 
 |  | ||||||
| 		let payload = {  |  | ||||||
| 			method: 'post',  |  | ||||||
| 			headers: { |  | ||||||
| 				'Content-Type': 'application/json' |  | ||||||
| 			}, |  | ||||||
| 			body: JSON.stringify({ |  | ||||||
| 				'email': this.state.email, |  | ||||||
| 				'password': this.state.password |  | ||||||
| 			}) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		fetch(api.url + '/user/login', payload) |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((response) => { |  | ||||||
| 			if (response.result == 'authenticated') { |  | ||||||
| 				localStorage.setItem('role', response.role) |  | ||||||
| 				localStorage.setItem('name', response.name) |  | ||||||
| 				localStorage.setItem('token', 'Bearer ' + response.token) |  | ||||||
| 				this.props.setUser() |  | ||||||
| 				this.setState({ |  | ||||||
| 					gotoMenu: true |  | ||||||
| 				}) |  | ||||||
| 			} else { |  | ||||||
| 				this.setState({ |  | ||||||
| 					errorMessage: <div className="alert alert-danger">{ response.error }</div> |  | ||||||
| 				}) |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	render() { |  | ||||||
| 		if (this.state.gotoMenu) { |  | ||||||
| 			return <Redirect to='/'/> |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		let url = this.props.urlParam  |  | ||||||
| 		let params = queryString.parse(url) |  | ||||||
| 		let registerSuccessMessage = null |  | ||||||
| 		let message = null |  | ||||||
| 
 |  | ||||||
| 		if (params.register_success) { |  | ||||||
| 			registerSuccessMessage = <div className="alert alert-success">Registration successful, you may now login.</div> |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (this.state.errorMessage == '' && registerSuccessMessage != null) { |  | ||||||
| 			message = registerSuccessMessage |  | ||||||
| 		} else { |  | ||||||
| 			message = this.state.errorMessage |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return( |  | ||||||
| 			<form onSubmit={ this.formSubmitHandler.bind(this) }> |  | ||||||
| 
 |  | ||||||
| 				{ message }					 |  | ||||||
| 
 |  | ||||||
| 				<label>Email</label> |  | ||||||
| 				<input value={ this.state.email } onChange={ this.emailChangeHandler.bind(this) } type="email" className="form-control"></input> |  | ||||||
| 
 |  | ||||||
| 				<label className="mt-2">Password</label> |  | ||||||
| 				<input value={ this.state.password } onChange={ this.passwordChangeHandler.bind(this) } type="password" className="form-control"></input> |  | ||||||
| 
 |  | ||||||
| 				<button type="submit" className="btn btn-success btn-block mt-3">Login</button> |  | ||||||
| 
 |  | ||||||
| 			</form>  |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default Login |  | ||||||
| @ -1,10 +0,0 @@ | |||||||
| import React from 'react' |  | ||||||
| import { Redirect } from 'react-router-dom' |  | ||||||
| 
 |  | ||||||
| const Logout = (props) => { |  | ||||||
| 	props.unsetUser() |  | ||||||
| 
 |  | ||||||
| 	return <Redirect to='/login'/> |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default Logout |  | ||||||
| @ -1,154 +0,0 @@ | |||||||
| import React, { Component } from 'react' |  | ||||||
| import { Link } from 'react-router-dom' |  | ||||||
| import api from '../api-proxy' |  | ||||||
| 
 |  | ||||||
| const Menu = (props) => { |  | ||||||
| 	document.title = 'Menu' |  | ||||||
| 	let btnAddItem = null |  | ||||||
| 
 |  | ||||||
| 	if (localStorage.getItem('role') == 'admin') { |  | ||||||
| 		btnAddItem = <Link className="btn btn-sm btn-primary" to="/item-create">Add Item</Link> |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	return ( |  | ||||||
| 		<div className="container-fluid mt-3"> |  | ||||||
| 			<h3>Items on the Menu</h3> |  | ||||||
| 			{ btnAddItem } |  | ||||||
| 			<MenuList getTotalCartQuantity={ props.getTotalCartQuantity }/> |  | ||||||
| 		</div> |  | ||||||
| 	)	 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class MenuList extends Component { |  | ||||||
| 
 |  | ||||||
| 	constructor(props) { |  | ||||||
| 		super(props) |  | ||||||
| 
 |  | ||||||
| 		this.state = { |  | ||||||
| 			items: [] |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	componentWillMount() { |  | ||||||
| 		fetch(api.url + '/items') |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((items) => { |  | ||||||
| 			this.setState({ items: items }) |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	render() { |  | ||||||
| 		return ( |  | ||||||
| 			<div className="row mt-3"> |  | ||||||
| 			{ |  | ||||||
| 				this.state.items.map((item) => { |  | ||||||
| 					return ( |  | ||||||
| 						<div key={ item._id } className="col-3 mb-3"> |  | ||||||
| 
 |  | ||||||
| 							<div className="card"> |  | ||||||
| 
 |  | ||||||
| 								<img className="card-img-top" width="100%" height="200px" style={ {objectFit: 'cover'} } src={ item.imageLocation }/> |  | ||||||
| 
 |  | ||||||
| 								<div className="card-body"> |  | ||||||
| 
 |  | ||||||
| 									<h4 className="card-title">{ item.name }</h4> |  | ||||||
| 
 |  | ||||||
| 									<p className="card-text">{ item.description }</p> |  | ||||||
| 
 |  | ||||||
| 									<p className="card-text">₱{ item.unitPrice }</p> |  | ||||||
| 
 |  | ||||||
| 									{ |  | ||||||
| 										(localStorage.getItem('role') == 'admin') ?  |  | ||||||
| 										( |  | ||||||
| 											<div className="btn-group btn-block"> |  | ||||||
| 												<Link className="btn btn-info" to={"/item-update?_id="+item._id }>Edit</Link> |  | ||||||
| 												<Link className="btn btn-danger" to={"/item-delete?_id="+item._id }>Delete</Link> |  | ||||||
| 											</div> |  | ||||||
| 										) :  |  | ||||||
| 										( |  | ||||||
| 											<AddToCartForm _id={ item._id } getTotalCartQuantity={ this.props.getTotalCartQuantity }/> |  | ||||||
| 										) |  | ||||||
| 									} |  | ||||||
| 
 |  | ||||||
| 								</div> |  | ||||||
| 
 |  | ||||||
| 							</div> |  | ||||||
| 
 |  | ||||||
| 						</div> |  | ||||||
| 					) |  | ||||||
| 				}) |  | ||||||
| 			} |  | ||||||
| 			</div> |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class AddToCartForm extends Component { |  | ||||||
| 
 |  | ||||||
| 	constructor(props) { |  | ||||||
| 		super(props) |  | ||||||
| 
 |  | ||||||
| 		this.state = { |  | ||||||
| 			_id: props._id, |  | ||||||
| 			quantity: 0 |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	quantityChangeHandler(e) { |  | ||||||
| 		this.setState({ quantity: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	formSubmitHandler(e) { |  | ||||||
| 		e.preventDefault() |  | ||||||
| 
 |  | ||||||
| 		let cart = JSON.parse(localStorage.getItem('cart')) |  | ||||||
| 
 |  | ||||||
| 		if (cart != null) { |  | ||||||
| 			for (let i = 0; i < cart.length; i++) { |  | ||||||
| 				if (cart[i]._id == this.state._id) { |  | ||||||
| 					cart[i].quantity = parseFloat(cart[i].quantity) + parseFloat(this.state.quantity) |  | ||||||
| 					 |  | ||||||
| 					localStorage.setItem('cart', JSON.stringify(cart)) |  | ||||||
| 					alert('Item has been added to cart') |  | ||||||
| 
 |  | ||||||
| 					this.setState({ quantity: 0 }) |  | ||||||
| 					this.props.getTotalCartQuantity() |  | ||||||
| 
 |  | ||||||
| 					return |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			cart.push({ |  | ||||||
| 				'_id': this.state._id, |  | ||||||
| 				'quantity': parseFloat(this.state.quantity) |  | ||||||
| 			}) |  | ||||||
| 		} else { |  | ||||||
| 			cart = [] |  | ||||||
| 			cart.push({ |  | ||||||
| 				'_id': this.state._id, |  | ||||||
| 				'quantity': parseFloat(this.state.quantity) |  | ||||||
| 			}) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		localStorage.setItem('cart', JSON.stringify(cart)) |  | ||||||
| 		alert('Item has been added to cart') |  | ||||||
| 
 |  | ||||||
| 		this.setState({ quantity: 0 }) |  | ||||||
| 		this.props.getTotalCartQuantity() |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	render() { |  | ||||||
| 		return ( |  | ||||||
| 			<form onSubmit={ this.formSubmitHandler.bind(this) }> |  | ||||||
| 				<div className="input-group">				 |  | ||||||
| 					<div className="input-group-prepend"> |  | ||||||
| 						<input value={ this.state.quantity } onChange={ this.quantityChangeHandler.bind(this) } type="number" className="form-control" min="1"/> |  | ||||||
| 						<button type="submit" className="btn btn-success btn-add-to-cart">Add</button> |  | ||||||
| 					</div>	 |  | ||||||
| 				</div> |  | ||||||
| 			</form> |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default Menu |  | ||||||
| @ -1,134 +0,0 @@ | |||||||
| import React, { Component } from 'react' |  | ||||||
| import { Redirect } from 'react-router-dom' |  | ||||||
| import api from '../api-proxy' |  | ||||||
| 
 |  | ||||||
| document.title = 'Register' |  | ||||||
| 
 |  | ||||||
| const Register = () => { |  | ||||||
| 	if (localStorage.getItem('token') != null) { |  | ||||||
| 		return <Redirect to='/'/> |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return ( |  | ||||||
| 		<div className="container-fluid mt-3"> |  | ||||||
| 
 |  | ||||||
| 			<div className="row"> |  | ||||||
| 			 |  | ||||||
| 				<div className="col-6 mx-auto"> |  | ||||||
| 					 |  | ||||||
| 					<h3 className="text-center">Registration Page</h3> |  | ||||||
| 
 |  | ||||||
| 					<div className="card"> |  | ||||||
| 						 |  | ||||||
| 						<div className="card-header">Registration Information</div> |  | ||||||
| 
 |  | ||||||
| 							<div className="card-body"> |  | ||||||
| 								 |  | ||||||
| 								<RegisterForm/> |  | ||||||
| 
 |  | ||||||
| 							</div> |  | ||||||
| 
 |  | ||||||
| 					</div>			 |  | ||||||
| 
 |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 			</div> |  | ||||||
| 			 |  | ||||||
| 		</div> |  | ||||||
| 	) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class RegisterForm extends Component { |  | ||||||
| 
 |  | ||||||
| 	constructor(props) { |  | ||||||
| 		super(props) |  | ||||||
| 
 |  | ||||||
| 		this.state = { |  | ||||||
| 			name:'', |  | ||||||
| 			email:'', |  | ||||||
| 			password:'', |  | ||||||
| 			gotoLogin: false, |  | ||||||
| 			isSubmitDisabled: true |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	nameChangeHandler(e) { |  | ||||||
| 		this.setState({ name: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	emailChangeHandler(e) { |  | ||||||
| 		this.setState({ email: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	passwordChangeHandler(e) { |  | ||||||
| 		if (e.target.value.length < 8) { |  | ||||||
| 			this.setState({ isSubmitDisabled: true }) |  | ||||||
| 		} else { |  | ||||||
| 			this.setState({ isSubmitDisabled: false }) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		this.setState({ password: e.target.value }) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	formSubmitHandler(e) { |  | ||||||
| 		e.preventDefault() |  | ||||||
| 
 |  | ||||||
| 		let payload = { |  | ||||||
| 			method: 'POST', |  | ||||||
| 			headers: { |  | ||||||
| 				'Content-Type': 'application/json' |  | ||||||
| 			}, |  | ||||||
| 			body: JSON.stringify({ |  | ||||||
| 				'name': this.state.name, |  | ||||||
| 				'email': this.state.email, |  | ||||||
| 				'password': this.state.password |  | ||||||
| 			}) |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		fetch(api.url + '/user/register', payload) |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((response) => { |  | ||||||
| 			if (response.error != null) { |  | ||||||
| 				alert(response.error) |  | ||||||
| 			} else { |  | ||||||
| 				this.setState({ gotoLogin: true }) |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	render() { |  | ||||||
| 		if (this.state.gotoLogin) { |  | ||||||
| 			return <Redirect to='/login?register_success=true'/> |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return ( |  | ||||||
| 			<form onSubmit= { this.formSubmitHandler.bind(this) }> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group">					 |  | ||||||
| 					<label>Name</label> |  | ||||||
| 					<input value={ this.state.name } onChange= { this.nameChangeHandler.bind(this) } type="text" className="form-control mb-1"/> |  | ||||||
| 					<span className="text-danger"></span> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group">					 |  | ||||||
| 					<label>Email</label> |  | ||||||
| 					<input value= { this.state.email } onChange={ this.emailChangeHandler.bind(this) } type="email" className="form-control mb-1"/> |  | ||||||
| 					<span className="text-danger"></span> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 				<div className="form-group">					 |  | ||||||
| 					<label>Password</label> |  | ||||||
| 					<input value= { this.state.password } onChange={ this.passwordChangeHandler.bind(this) } type="password" className="form-control mb-1"/> |  | ||||||
| 					<span className="text-danger"></span> |  | ||||||
| 				</div> |  | ||||||
| 
 |  | ||||||
| 				<button disabled={ this.state.isSubmitDisabled } type="submit" className="btn btn-success btn-block">Register</button> |  | ||||||
| 
 |  | ||||||
| 			</form> |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default Register |  | ||||||
| @ -1,70 +0,0 @@ | |||||||
| import React, { Component } from 'react' |  | ||||||
| import api from '../api-proxy' |  | ||||||
| 
 |  | ||||||
| document.title = 'Transactions' |  | ||||||
| 
 |  | ||||||
| class Transactions extends Component { |  | ||||||
| 
 |  | ||||||
| 	constructor(props) { |  | ||||||
| 		super(props) |  | ||||||
| 
 |  | ||||||
| 		this.state = { |  | ||||||
| 			orders: [] |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	componentWillMount() { |  | ||||||
| 		let payload = { |  | ||||||
| 			method: 'get', |  | ||||||
| 			headers: { |  | ||||||
| 				authorization: localStorage.getItem('token') |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		fetch(api.url + '/orders/user', payload) |  | ||||||
| 		.then((response) => response.json()) |  | ||||||
| 		.then((response) => { |  | ||||||
| 			if (response.error == 'token-auth-failed' || response.error == 'undefined-auth-header') { |  | ||||||
| 				window.location.href = '/login' |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			this.setState({ orders: response }) |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	render() { |  | ||||||
| 		return ( |  | ||||||
| 			<div className="container-fluid mt-3"> |  | ||||||
| 
 |  | ||||||
| 				<h3>Transactions</h3> |  | ||||||
| 
 |  | ||||||
| 				<table className="table table-bordered"> |  | ||||||
| 
 |  | ||||||
| 					<thead> |  | ||||||
| 						<tr> |  | ||||||
| 							<th>Order ID</th> |  | ||||||
| 							<th>Total Price</th> |  | ||||||
| 							<th>Order Datetime</th> |  | ||||||
| 						</tr> |  | ||||||
| 					</thead> |  | ||||||
| 
 |  | ||||||
| 					<tbody> |  | ||||||
| 						{ |  | ||||||
| 							this.state.orders.map((order)=> { |  | ||||||
| 								return <tr> |  | ||||||
| 									<td>{ order._id }</td> |  | ||||||
| 									<td className="text-right">{ order.totalPrice.toFixed(2) }</td> |  | ||||||
| 									<td>{ new Date(order.datetimeRecorded).toLocaleString() }</td> |  | ||||||
| 								</tr> |  | ||||||
| 							}) |  | ||||||
| 						} |  | ||||||
| 					</tbody> |  | ||||||
| 
 |  | ||||||
| 				</table> |  | ||||||
| 				 |  | ||||||
| 			</div> |  | ||||||
| 		) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default Transactions |  | ||||||
| @ -1,8 +0,0 @@ | |||||||
| import 'bootstrap/dist/css/bootstrap.min.css' |  | ||||||
| import 'bootstrap/dist/js/bootstrap.bundle.min' |  | ||||||
| 
 |  | ||||||
| import React from 'react' |  | ||||||
| import ReactDOM from 'react-dom' |  | ||||||
| import App from './components/App' |  | ||||||
| 
 |  | ||||||
| ReactDOM.render(<App/>, document.getElementById('root')) |  | ||||||
| Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB | 
| Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB | 
| Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |