diff --git a/Procfile b/Procfile deleted file mode 100644 index 0aaef48..0000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -web: node dist/server.js \ No newline at end of file diff --git a/README.md b/README.md index 2f05f4f..b4cb681 100644 --- a/README.md +++ b/README.md @@ -1,266 +1,18 @@ -# React & Node Tutorial - Full ECommerce in 5 Hours [2020] +# Projeto e-co realizado para o Hackathon Call for Code - IBM + +## Escolhemos o desafio 3. Nosso projeto é um marketplace para pequenos agricultores e artesãos. + +## Instalando +### Para instalar as dependências do projeto, execute os seguintes comandos no terminal: +#### - npm install +#### - npm start + +## Tecnologias utilizadas +#### - React +#### - Cloudant + +## Link do site +https://call-for-code-2021.us-south.cf.appdomain.cloud/ -Welcome to my React and Node tutorial to build a fully-functional e-commerce website in 5 hours. Open your code editor and follow me for the next hours to build an e-commerce website using React and Node.JS. -## Demo Website -👉 Demo : https://oldamazona.webacademy.pro - -## Video Tutorial - -👉 Click on this image to watch full 5-hours video of this tutorial - -[![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/Fy9SdZLBTOo/0.jpg)](https://www.youtube.com/watch?v=Fy9SdZLBTOo) - -## You Will Learn - -- HTML5 and CSS3: Semantic Elements, CSS Grid, Flexbox -- React: Components, Props, Events, Hooks, Router, Axios -- Redux: Store, Reducers, Actions -- Node & Express: Web API, Body Parser, File Upload, JWT -- MongoDB: Mongoose, Aggregation -- Development: ESLint, Babel, Git, Github, -- Deployment: Heroku -- Watch React & Node Tutorial - -## Run Locally - -### 1. Clone repo - -``` -$ git clone git@github.com:basir/node-react-ecommerce.git -$ cd node-react-ecommerce -``` - -### 2. Install MongoDB - -Download it from here: https://docs.mongodb.com/manual/administration/install-community/ - -### 3. Run Backend - -``` -$ npm install -$ npm start -``` - -### 4. Run Frontend - -``` -# open new terminal -$ cd frontend -$ npm install -$ npm start -``` - -### 5. Create Admin User - -- Run this on chrome: http://localhost:5000/api/users/createadmin -- It returns admin email and password - -### 6. Login - -- Run http://localhost:3000/signin -- Enter admin email and password and click signin - -### 7. Create Products - -- Run http://localhost:3000/products -- Click create product and enter product info - -## Support - -- Q/A: https://webacademy.pro/oldamazona -- Contact Instructor: [Basir](mailto:basir.jafarzadeh@gmail.com) - -## Video Tutorials - -### [00:02:00 Part 01- Introduction](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=120s) - -It gives you an overview of the tutorial to build an eCommerce website like Amazon. - -### [00:08:26 Part 02- Install Tools](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=506s) - -You need to install a code editor and a web browser to start web development. In this part, we will prepare the environment to start coding. - -### [00:12:36 Part 03- Website Template](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=756s) - -In this part, you create a web template for the eCommerce website. -![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/56kqn8m5n1m9fejdoxkz.png) - -### [00:29:47 Part 04- Products List](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=1787s) - -We will create a list of products as static HTML elements. - -### [00:41:54 Part 05- Create Sidebar](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=2514s) - -We will create a hamburger menu that shows and hide the sidebar. Also, we design the details page of the products. -![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3sceblg6i6790minhaxg.jpg) - -### [00:52:39 Part 06- Create React App](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=3159s) - -This part is about the frontend. We use React library to build the UI elements. - -### [01:01:09 Part 07- Render Products](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=3669s) - -This is the home page of e-commerce. It shows a list of products. -![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/hqiwteg10o8a2cnq0wwi.jpg) - -### [01:06:30 Part 08- Product Details](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=3990s) - -When the user clicks on a product there should a page to show details about that product. This lesson is all about making an attractive details page. -![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/csskvzbcmz4ypki2xjgk.jpg) - -### [01:30:53 Part 09- Create Node Server](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=5453s) - -This part is about Node and Express. They are the popular framework to create a web server using JavaScript language. We will create a MongoDB database and save and retrieve the admin user. - -### [01:39:52 Part 10- Fetch Server Data](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=5992s) - -In this lesson, we use React Hooks to fetch data from the server. We use the axios library to do this job in a modern async/await style. - -### [01:47:55 Part 11- Manage State With Redux](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=6475s) - -When it comes to handling multiple forms with their data nothing is better than state management. We use Redux in this lesson to handle complex state and keep the app behavior predictable. - -### [02:07:11 Part 12- Add Redux To Details](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=7631s) - -In this part, we move the details page state to Redux. First, we create reducers then define actions and connect them to the details component. - -### [02:29:23 Part 13- Shopping Cart Screen](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=8963s) - -Shopping Cart is the heart of any e-commerce website. We focus on creating a user-friendly shopping cart using React and Redux. -![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fyzf0no5ej1fgxp5972e.png) - -### [03:08:11 Part 14- Connect MongoDB](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=11291s) - -This lesson is about persisting data on the MongoDB database. We use mongoose package to create models and save and retrieve data from the database. - -### [03:21:35 Part 15- Sign In User](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=12095s) - -We need to register the user before redirecting them to the checkout. In this part, we will create forms for getting user info and save them in the database. -![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/92coj0rezr5508vhfv34.png) - -### [03:56:02 Part 16- Manage Products](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=14162s) - -Admin should be able to define products and update the count in stock whenever they like. This page is about managing ECommerce products. -![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/154a5zk6vfapukjaxwyu.png) - -### [04:38:43 Part 17- Checkout Wizard](https://www.youtube.com/watch?v=Fy9SdZLBTOo&t=16723s) - -In this part, we implement the checkout wizard including sign in, shipping info, payment method, and place order. -![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/l8w3g9mc3ccijt70wpf3.png) - -## Only On Udemy - -Following parts are on my udemy course. [Get it by 90% discount](https://www.udemy.com/course/build-ecommerce-website-like-amazon-react-node-mongodb/?couponCode=BASIR1) - -### Part 18- Order Details Screen - -It shows all details about an order includeing shipping, payments and order items. Also it is possible for admin to manage orders like set them as delivered. - -### Part 19- Connect to PayPal - -This parts create PaypalButton component to show paypal payment button on the screen. -when users click on it, they will be redirected to paypal website to make the payment. -after payment users will be redirected to details page of the order. - -### Part 20- Manage Order Screen - -This is an admin page to manage list of orders. Admin can delete an order or set it as delivered. - -### Part 21- User Profile Screen - -When user click on thier name on the header menu, this page appears. It consists of two sections. First an profile update form and second order history. - -### Part 22- Filter and Sort Products - -In the home page, right after header, there is a filter bar to filter products based on their name and description. also it is possible to sort product based on prices and arrivals. - -### Part 23- Deploy Website on Heroku - -This section explains all steps to publish the ecommerce website on heroku. first you need to create a cloud mongodb and the make an account on heroku. - -### Part 24- Rate and Review Products - -This part shows list of reviews by users for each products. also it provides a form to enter rating and review for every single product. also it update the avg rating of each product by user ratings. - -1. index.html -2. link fontawesome -3. Rating.js -4. create stars based on props.value -5. show text based on props.text -6. index.css -7. style rating, span color gold and last span to gray, link text to blue -8. HomeScreen.js -9. use Rating component -10. ProductScreen.js -11. use Rating component, wrap it in anchor#reviews -12. list reviews after product details -13. create new review form to get rating and reviews -14. index.css -15. style reviews -16. ProductScreen.js -17. implement submitHandler -18. productActions.js -19. create saveProductReview(productId, review) -20. productConstants.js -21. create product review constants -22. productReducers.js -23. create productReviewSaveReducer -24. store.js -25. add productReviewSaveReducer -26. backend -27. productRoute.js -28. router.post('/:id/reviews') -29. save review in product.reviews -30. update avg rating - -### Part 25- Upload Product Images On Local Server - -Admin shoud be able to uploads photos from their computer. This section is about uploading images on local server ans aws s3 cloud server. - -1. npm install multer -2. 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. server.js -9. app.use('/api/uploads',uploadRoute) -10. ProductsScreen.js -11. create state hook for uploading -12. create input image file and onChange handler -13. define handleUploadImage function -14. prepare file for upload -15. axios post file as multipart/form-data -16. set image and set uploading -17. check result - -### Part 26- Upload Product Images On AWS S3 - -This section is about uploading images amazon aws s3 cloud server. - -1. create aws account -2. open https://s3.console.aws.amazon.com -3. create public bucket as amazona -4. create api key and secret -5. past it into .env as accessKeyId and secretAccessKey -6. move dotenv to config.js -7. add accessKeyId and secretAccessKey to config.js -8. npm install aws-sdk multer-s3 -9. routes/uploadRoute.js -10. set aws.config.update to config values -11. create s3 from new aws.S3() -12. create storageS3 from multerS3 by setting s3, bucket and acl -13. set uploadS3 as multer({ storage: storageS3 }) -14. router.post('/s3', uploadS3.single('image')) -15. return req.file.location -16. ProductsScreen.js -17. on handleUploadImage set axios.post('api/uploads/s3') -18. check result on website and s3 - -## Summary - -In this tutorial, we have made an eCommerce website like Amazon. Feel free to change this project based on your needs and add it to your portfolio. -Also, I will love to hear your comment about this React and Node tutorial. Please share your thoughts here. diff --git a/backend/config.js b/backend/config.js deleted file mode 100644 index 4467a7d..0000000 --- a/backend/config.js +++ /dev/null @@ -1,12 +0,0 @@ -import dotenv from 'dotenv'; - -dotenv.config(); - -export default { - PORT: process.env.PORT || 5000, - MONGODB_URL: process.env.MONGODB_URL || 'mongodb://localhost/amazona', - JWT_SECRET: process.env.JWT_SECRET || 'somethingsecret', - PAYPAL_CLIENT_ID: process.env.PAYPAL_CLIENT_ID || 'sb', - accessKeyId: process.env.accessKeyId || 'accessKeyId', - secretAccessKey: process.env.secretAccessKey || 'secretAccessKey', -}; diff --git a/backend/data.js b/backend/data.js deleted file mode 100644 index df964e3..0000000 --- a/backend/data.js +++ /dev/null @@ -1,46 +0,0 @@ -export default { - products: [ - { - _id: '1', - name: 'Slim Shirt', - category: 'Shirts', - image: '/images/d1.jpg', - price: 60, - brand: ' Nike', - rating: 4.5, - numReviews: 10, - countInStock: 6, - }, - { - _id: '2', - name: 'Fit Shirt', - category: 'Shirts', - image: '/images/d1.jpg', - price: 50, - brand: ' Nike', - rating: 4.2, - numReviews: 5 - }, - { - _id: '3', - name: 'Best Pants', - category: 'Pants', - image: '/images/d1.jpg', - price: 70, - brand: ' Nike', - rating: 4.5, - numReviews: 8, - countInStock: 6, - }, { - _id: '4', - name: 'Best Pants', - category: 'Pants', - image: '/images/d1.jpg', - price: 70, - brand: ' Nike', - rating: 4.5, - numReviews: 8, - countInStock: 6, - }, - ] -} \ No newline at end of file diff --git a/backend/models/orderModel.js b/backend/models/orderModel.js deleted file mode 100644 index 8871d25..0000000 --- a/backend/models/orderModel.js +++ /dev/null @@ -1,43 +0,0 @@ -import mongoose from 'mongoose'; -const shippingSchema = { - address: { type: String, required: true }, - city: { type: String, required: true }, - postalCode: { type: String, required: true }, - country: { type: String, required: true }, -}; - -const paymentSchema = { - paymentMethod: { type: String, required: true } -}; - -const orderItemSchema = new mongoose.Schema({ - name: { type: String, required: true }, - qty: { type: Number, required: true }, - image: { type: String, required: true }, - price: { type: String, required: true }, - product: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Product', - required: true - }, -}); - -const orderSchema = new mongoose.Schema({ - user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, - orderItems: [orderItemSchema], - shipping: shippingSchema, - payment: paymentSchema, - itemsPrice: { type: Number }, - taxPrice: { type: Number }, - shippingPrice: { type: Number }, - totalPrice: { type: Number }, - isPaid: { type: Boolean, default: false }, - paidAt: { type: Date }, - isDelivered: { type: Boolean, default: false }, - deliveredAt: { type: Date }, -}, { - timestamps: true -}); - -const orderModel = mongoose.model("Order", orderSchema); -export default orderModel; \ No newline at end of file diff --git a/backend/models/productModel.js b/backend/models/productModel.js deleted file mode 100644 index 7c60507..0000000 --- a/backend/models/productModel.js +++ /dev/null @@ -1,28 +0,0 @@ -import mongoose from 'mongoose'; - -const reviewSchema = new mongoose.Schema( - { - name: { type: String, required: true }, - rating: { type: Number, default: 0 }, - comment: { type: String, required: true }, - }, - { - timestamps: true, - } -); -const prodctSchema = new mongoose.Schema({ - name: { type: String, required: true }, - image: { type: String, required: true }, - brand: { type: String, required: true }, - price: { type: Number, default: 0, required: true }, - category: { type: String, required: true }, - countInStock: { type: Number, default: 0, required: true }, - description: { type: String, required: true }, - rating: { type: Number, default: 0, required: true }, - numReviews: { type: Number, default: 0, required: true }, - reviews: [reviewSchema], -}); - -const productModel = mongoose.model('Product', prodctSchema); - -export default productModel; diff --git a/backend/models/userModel.js b/backend/models/userModel.js deleted file mode 100644 index d33b083..0000000 --- a/backend/models/userModel.js +++ /dev/null @@ -1,14 +0,0 @@ -import mongoose from 'mongoose'; - -const userSchema = new mongoose.Schema({ - name: { type: String, required: true }, - email: { - type: String, required: true, unique: true, index: true, dropDups: true, - }, - password: { type: String, required: true }, - isAdmin: { type: Boolean, required: true, default: false }, -}); - -const userModel = mongoose.model('User', userSchema); - -export default userModel; diff --git a/backend/routes/orderRoute.js b/backend/routes/orderRoute.js deleted file mode 100644 index ad9181a..0000000 --- a/backend/routes/orderRoute.js +++ /dev/null @@ -1,70 +0,0 @@ -import express from 'express'; -import Order from '../models/orderModel'; -import { isAuth, isAdmin } from '../util'; - -const router = express.Router(); - -router.get("/", isAuth, async (req, res) => { - const orders = await Order.find({}).populate('user'); - res.send(orders); -}); -router.get("/mine", isAuth, async (req, res) => { - const orders = await Order.find({ user: req.user._id }); - res.send(orders); -}); - -router.get("/:id", isAuth, async (req, res) => { - const order = await Order.findOne({ _id: req.params.id }); - if (order) { - res.send(order); - } else { - res.status(404).send("Order Not Found.") - } -}); - -router.delete("/:id", isAuth, isAdmin, async (req, res) => { - const order = await Order.findOne({ _id: req.params.id }); - if (order) { - const deletedOrder = await order.remove(); - res.send(deletedOrder); - } else { - res.status(404).send("Order Not Found.") - } -}); - -router.post("/", isAuth, async (req, res) => { - const newOrder = new Order({ - orderItems: req.body.orderItems, - user: req.user._id, - shipping: req.body.shipping, - payment: req.body.payment, - itemsPrice: req.body.itemsPrice, - taxPrice: req.body.taxPrice, - shippingPrice: req.body.shippingPrice, - totalPrice: req.body.totalPrice, - }); - const newOrderCreated = await newOrder.save(); - res.status(201).send({ message: "New Order Created", data: newOrderCreated }); -}); - -router.put("/:id/pay", isAuth, async (req, res) => { - const order = await Order.findById(req.params.id); - if (order) { - order.isPaid = true; - order.paidAt = Date.now(); - order.payment = { - paymentMethod: 'paypal', - paymentResult: { - payerID: req.body.payerID, - orderID: req.body.orderID, - paymentID: req.body.paymentID - } - } - const updatedOrder = await order.save(); - res.send({ message: 'Order Paid.', order: updatedOrder }); - } else { - res.status(404).send({ message: 'Order not found.' }) - } -}); - -export default router; \ No newline at end of file diff --git a/backend/routes/productRoute.js b/backend/routes/productRoute.js deleted file mode 100644 index 8bc2799..0000000 --- a/backend/routes/productRoute.js +++ /dev/null @@ -1,110 +0,0 @@ -import express from 'express'; -import Product from '../models/productModel'; -import { isAuth, isAdmin } from '../util'; - -const router = express.Router(); - -router.get('/', async (req, res) => { - const category = req.query.category ? { category: req.query.category } : {}; - const searchKeyword = req.query.searchKeyword - ? { - name: { - $regex: req.query.searchKeyword, - $options: 'i', - }, - } - : {}; - const sortOrder = req.query.sortOrder - ? req.query.sortOrder === 'lowest' - ? { price: 1 } - : { price: -1 } - : { _id: -1 }; - const products = await Product.find({ ...category, ...searchKeyword }).sort( - sortOrder - ); - res.send(products); -}); - -router.get('/:id', async (req, res) => { - const product = await Product.findOne({ _id: req.params.id }); - if (product) { - res.send(product); - } else { - res.status(404).send({ message: 'Product Not Found.' }); - } -}); -router.post('/:id/reviews', isAuth, async (req, res) => { - const product = await Product.findById(req.params.id); - if (product) { - const review = { - name: req.body.name, - rating: Number(req.body.rating), - comment: req.body.comment, - }; - product.reviews.push(review); - product.numReviews = product.reviews.length; - product.rating = - product.reviews.reduce((a, c) => c.rating + a, 0) / - product.reviews.length; - const updatedProduct = await product.save(); - res.status(201).send({ - data: updatedProduct.reviews[updatedProduct.reviews.length - 1], - message: 'Review saved successfully.', - }); - } else { - res.status(404).send({ message: 'Product Not Found' }); - } -}); -router.put('/:id', isAuth, isAdmin, async (req, res) => { - const productId = req.params.id; - const product = await Product.findById(productId); - if (product) { - product.name = req.body.name; - product.price = req.body.price; - product.image = req.body.image; - product.brand = req.body.brand; - product.category = req.body.category; - product.countInStock = req.body.countInStock; - product.description = req.body.description; - const updatedProduct = await product.save(); - if (updatedProduct) { - return res - .status(200) - .send({ message: 'Product Updated', data: updatedProduct }); - } - } - return res.status(500).send({ message: ' Error in Updating Product.' }); -}); - -router.delete('/:id', isAuth, isAdmin, async (req, res) => { - const deletedProduct = await Product.findById(req.params.id); - if (deletedProduct) { - await deletedProduct.remove(); - res.send({ message: 'Product Deleted' }); - } else { - res.send('Error in Deletion.'); - } -}); - -router.post('/', isAuth, isAdmin, async (req, res) => { - const product = new Product({ - name: req.body.name, - price: req.body.price, - image: req.body.image, - brand: req.body.brand, - category: req.body.category, - countInStock: req.body.countInStock, - description: req.body.description, - rating: req.body.rating, - numReviews: req.body.numReviews, - }); - const newProduct = await product.save(); - if (newProduct) { - return res - .status(201) - .send({ message: 'New Product Created', data: newProduct }); - } - return res.status(500).send({ message: ' Error in Creating Product.' }); -}); - -export default router; diff --git a/backend/routes/uploadRoute.js b/backend/routes/uploadRoute.js deleted file mode 100644 index c962954..0000000 --- a/backend/routes/uploadRoute.js +++ /dev/null @@ -1,42 +0,0 @@ -import express from 'express'; -import multer from 'multer'; -import multerS3 from 'multer-s3'; -import aws from 'aws-sdk'; -import config from '../config'; - -const storage = multer.diskStorage({ - destination(req, file, cb) { - cb(null, 'uploads/'); - }, - filename(req, file, cb) { - cb(null, `${Date.now()}.jpg`); - }, -}); - -const upload = multer({ storage }); - -const router = express.Router(); - -router.post('/', upload.single('image'), (req, res) => { - res.send(`/${req.file.path}`); -}); - -aws.config.update({ - accessKeyId: config.accessKeyId, - secretAccessKey: config.secretAccessKey, -}); -const s3 = new aws.S3(); -const storageS3 = multerS3({ - s3, - bucket: 'amazona-bucket', - acl: 'public-read', - contentType: multerS3.AUTO_CONTENT_TYPE, - key(req, file, cb) { - cb(null, file.originalname); - }, -}); -const uploadS3 = multer({ storage: storageS3 }); -router.post('/s3', uploadS3.single('image'), (req, res) => { - res.send(req.file.location); -}); -export default router; diff --git a/backend/routes/userRoute.js b/backend/routes/userRoute.js deleted file mode 100644 index 40ab7d4..0000000 --- a/backend/routes/userRoute.js +++ /dev/null @@ -1,80 +0,0 @@ -import express from 'express'; -import User from '../models/userModel'; -import { getToken, isAuth } from '../util'; - -const router = express.Router(); - -router.put('/:id', isAuth, async (req, res) => { - const userId = req.params.id; - const user = await User.findById(userId); - if (user) { - user.name = req.body.name || user.name; - user.email = req.body.email || user.email; - user.password = req.body.password || user.password; - const updatedUser = await user.save(); - res.send({ - _id: updatedUser.id, - name: updatedUser.name, - email: updatedUser.email, - isAdmin: updatedUser.isAdmin, - token: getToken(updatedUser), - }); - } else { - res.status(404).send({ message: 'User Not Found' }); - } -}); - -router.post('/signin', async (req, res) => { - const signinUser = await User.findOne({ - email: req.body.email, - password: req.body.password, - }); - if (signinUser) { - res.send({ - _id: signinUser.id, - name: signinUser.name, - email: signinUser.email, - isAdmin: signinUser.isAdmin, - token: getToken(signinUser), - }); - } else { - res.status(401).send({ message: 'Invalid Email or Password.' }); - } -}); - -router.post('/register', async (req, res) => { - const user = new User({ - name: req.body.name, - email: req.body.email, - password: req.body.password, - }); - const newUser = await user.save(); - if (newUser) { - res.send({ - _id: newUser.id, - name: newUser.name, - email: newUser.email, - isAdmin: newUser.isAdmin, - token: getToken(newUser), - }); - } else { - res.status(401).send({ message: 'Invalid User Data.' }); - } -}); - -router.get('/createadmin', async (req, res) => { - try { - const user = new User({ - name: 'Basir', - email: 'admin@example.com', - password: '1234', - isAdmin: true, - }); - const newUser = await user.save(); - res.send(newUser); - } catch (error) { - res.send({ message: error.message }); - } -}); - -export default router; diff --git a/backend/server.js b/backend/server.js deleted file mode 100644 index f3abd1c..0000000 --- a/backend/server.js +++ /dev/null @@ -1,37 +0,0 @@ -import express from 'express'; -import path from 'path'; -import mongoose from 'mongoose'; -import bodyParser from 'body-parser'; -import config from './config'; -import userRoute from './routes/userRoute'; -import productRoute from './routes/productRoute'; -import orderRoute from './routes/orderRoute'; -import uploadRoute from './routes/uploadRoute'; - -const mongodbUrl = config.MONGODB_URL; -mongoose - .connect(mongodbUrl, { - useNewUrlParser: true, - useUnifiedTopology: true, - useCreateIndex: true, - }) - .catch((error) => console.log(error.reason)); - -const app = express(); -app.use(bodyParser.json()); -app.use('/api/uploads', uploadRoute); -app.use('/api/users', userRoute); -app.use('/api/products', productRoute); -app.use('/api/orders', orderRoute); -app.get('/api/config/paypal', (req, res) => { - res.send(config.PAYPAL_CLIENT_ID); -}); -app.use('/uploads', express.static(path.join(__dirname, '/../uploads'))); -app.use(express.static(path.join(__dirname, '/../frontend/build'))); -app.get('*', (req, res) => { - res.sendFile(path.join(`${__dirname}/../frontend/build/index.html`)); -}); - -app.listen(config.PORT, () => { - console.log('Server started at http://localhost:5000'); -}); diff --git a/backend/util.js b/backend/util.js deleted file mode 100644 index 36504db..0000000 --- a/backend/util.js +++ /dev/null @@ -1,44 +0,0 @@ -import jwt from 'jsonwebtoken'; -import config from './config'; -const getToken = (user) => { - return jwt.sign( - { - _id: user._id, - name: user.name, - email: user.email, - isAdmin: user.isAdmin, - }, - config.JWT_SECRET, - { - expiresIn: '48h', - } - ); -}; - -const isAuth = (req, res, next) => { - const token = req.headers.authorization; - - if (token) { - const onlyToken = token.slice(7, token.length); - jwt.verify(onlyToken, config.JWT_SECRET, (err, decode) => { - if (err) { - return res.status(401).send({ message: 'Invalid Token' }); - } - req.user = decode; - next(); - return; - }); - } else { - return res.status(401).send({ message: 'Token is not supplied.' }); - } -}; - -const isAdmin = (req, res, next) => { - console.log(req.user); - if (req.user && req.user.isAdmin) { - return next(); - } - return res.status(401).send({ message: 'Admin Token is not valid.' }); -}; - -export { getToken, isAuth, isAdmin }; diff --git a/frontend/package.json b/frontend/package.json deleted file mode 100644 index d8b2e58..0000000 --- a/frontend/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "frontend", - "proxy": "http://127.0.0.1:5000", - "version": "0.1.0", - "private": true, - "dependencies": { - "@testing-library/jest-dom": "^4.2.4", - "@testing-library/react": "^9.3.2", - "@testing-library/user-event": "^7.1.2", - "axios": "^0.19.2", - "js-cookie": "^2.2.1", - "react": "^16.12.0", - "react-dom": "^16.12.0", - "react-redux": "^7.1.3", - "react-router-dom": "^5.1.2", - "react-scripts": "^3.4.1", - "redux": "^4.0.5", - "redux-thunk": "^2.3.0" - }, - "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" - ] - } -} diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico deleted file mode 100644 index a11777c..0000000 Binary files a/frontend/public/favicon.ico and /dev/null differ diff --git a/frontend/public/logo192.png b/frontend/public/logo192.png deleted file mode 100644 index fc44b0a..0000000 Binary files a/frontend/public/logo192.png and /dev/null differ diff --git a/frontend/public/logo512.png b/frontend/public/logo512.png deleted file mode 100644 index a4e47a6..0000000 Binary files a/frontend/public/logo512.png and /dev/null differ diff --git a/frontend/src/App.js b/frontend/src/App.js deleted file mode 100644 index 0b2a186..0000000 --- a/frontend/src/App.js +++ /dev/null @@ -1,94 +0,0 @@ -import React from 'react'; -import { BrowserRouter, Route, Link } from 'react-router-dom'; -import './App.css'; -import HomeScreen from './screens/HomeScreen'; -import ProductScreen from './screens/ProductScreen'; -import CartScreen from './screens/CartScreen'; -import SigninScreen from './screens/SigninScreen'; -import { useSelector } from 'react-redux'; -import RegisterScreen from './screens/RegisterScreen'; -import ProductsScreen from './screens/ProductsScreen'; -import ShippingScreen from './screens/ShippingScreen'; -import PaymentScreen from './screens/PaymentScreen'; -import PlaceOrderScreen from './screens/PlaceOrderScreen'; -import OrderScreen from './screens/OrderScreen'; -import ProfileScreen from './screens/ProfileScreen'; -import OrdersScreen from './screens/OrdersScreen'; - -function App() { - const userSignin = useSelector((state) => state.userSignin); - const { userInfo } = userSignin; - - const openMenu = () => { - document.querySelector('.sidebar').classList.add('open'); - }; - const closeMenu = () => { - document.querySelector('.sidebar').classList.remove('open'); - }; - return ( - -
-
-
- - amazona -
-
- Cart - {userInfo ? ( - {userInfo.name} - ) : ( - Sign In - )} - {userInfo && userInfo.isAdmin && ( -
- Admin -
    -
  • - Orders - Products -
  • -
-
- )} -
-
- -
-
- - - - - - - - - - - - - -
-
- -
-
- ); -} - -export default App; diff --git a/frontend/src/screens/CartScreen.js b/frontend/src/screens/CartScreen.js deleted file mode 100644 index 1a25d6b..0000000 --- a/frontend/src/screens/CartScreen.js +++ /dev/null @@ -1,92 +0,0 @@ -import React, { useEffect } from 'react'; -import { addToCart, removeFromCart } from '../actions/cartActions'; -import { useDispatch, useSelector } from 'react-redux'; -import { Link } from 'react-router-dom'; -function CartScreen(props) { - - const cart = useSelector(state => state.cart); - - const { cartItems } = cart; - - const productId = props.match.params.id; - const qty = props.location.search ? Number(props.location.search.split("=")[1]) : 1; - const dispatch = useDispatch(); - const removeFromCartHandler = (productId) => { - dispatch(removeFromCart(productId)); - } - useEffect(() => { - if (productId) { - dispatch(addToCart(productId, qty)); - } - }, []); - - const checkoutHandler = () => { - props.history.push("/signin?redirect=shipping"); - } - - return
-
- - -
-
-

- Subtotal ( {cartItems.reduce((a, c) => a + c.qty, 0)} items) - : - $ {cartItems.reduce((a, c) => a + c.price * c.qty, 0)} -

- - -
- -
-} - -export default CartScreen; \ No newline at end of file diff --git a/frontend/src/screens/HomeScreen.js b/frontend/src/screens/HomeScreen.js deleted file mode 100644 index 3fa957b..0000000 --- a/frontend/src/screens/HomeScreen.js +++ /dev/null @@ -1,90 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { Link } from 'react-router-dom'; -import axios from 'axios'; -import { useSelector, useDispatch } from 'react-redux'; -import { listProducts } from '../actions/productActions'; -import Rating from '../components/Rating'; - -function HomeScreen(props) { - const [searchKeyword, setSearchKeyword] = useState(''); - const [sortOrder, setSortOrder] = useState(''); - const category = props.match.params.id ? props.match.params.id : ''; - const productList = useSelector((state) => state.productList); - const { products, loading, error } = productList; - const dispatch = useDispatch(); - useEffect(() => { - dispatch(listProducts(category)); - - return () => { - // - }; - }, [category]); - - const submitHandler = (e) => { - e.preventDefault(); - dispatch(listProducts(category, searchKeyword, sortOrder)); - }; - const sortHandler = (e) => { - setSortOrder(e.target.value); - dispatch(listProducts(category, searchKeyword, sortOrder)); - }; - - return ( - <> - {category &&

{category}

} - - - {loading ? ( -
Loading...
- ) : error ? ( -
{error}
- ) : ( - - )} - - ); -} -export default HomeScreen; diff --git a/frontend/src/screens/OrderScreen.js b/frontend/src/screens/OrderScreen.js deleted file mode 100644 index 60e3b0c..0000000 --- a/frontend/src/screens/OrderScreen.js +++ /dev/null @@ -1,137 +0,0 @@ -import React, { useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { Link } from 'react-router-dom'; -import { createOrder, detailsOrder, payOrder } from '../actions/orderActions'; -import PaypalButton from '../components/PaypalButton'; -function OrderScreen(props) { - - const orderPay = useSelector(state => state.orderPay); - const { loading: loadingPay, success: successPay, error: errorPay } = orderPay; - const dispatch = useDispatch(); - useEffect(() => { - if (successPay) { - props.history.push("/profile"); - } else { - dispatch(detailsOrder(props.match.params.id)); - } - return () => { - }; - }, [successPay]); - - const handleSuccessPayment = (paymentResult) => { - dispatch(payOrder(order, paymentResult)); - } - - const orderDetails = useSelector(state => state.orderDetails); - const { loading, order, error } = orderDetails; - - return loading ?
Loading ...
: error ?
{error}
: - -
-
-
-
-

- Shipping -

-
- {order.shipping.address}, {order.shipping.city}, - {order.shipping.postalCode}, {order.shipping.country}, -
-
- {order.isDelivered ? "Delivered at " + order.deliveredAt : "Not Delivered."} -
-
-
-

Payment

-
- Payment Method: {order.payment.paymentMethod} -
-
- {order.isPaid ? "Paid at " + order.paidAt : "Not Paid."} -
-
-
-
    -
  • -

    - Shopping Cart -

    -
    - Price -
    -
  • - { - order.orderItems.length === 0 ? -
    - Cart is empty -
    - : - order.orderItems.map(item => -
  • -
    - product -
    -
    -
    - - {item.name} - - -
    -
    - Qty: {item.qty} -
    -
    -
    - ${item.price} -
    -
  • - ) - } -
-
- - -
-
-
    -
  • - {loadingPay &&
    Finishing Payment...
    } - {!order.isPaid && - - } -
  • -
  • -

    Order Summary

    -
  • -
  • -
    Items
    -
    ${order.itemsPrice}
    -
  • -
  • -
    Shipping
    -
    ${order.shippingPrice}
    -
  • -
  • -
    Tax
    -
    ${order.taxPrice}
    -
  • -
  • -
    Order Total
    -
    ${order.totalPrice}
    -
  • -
- - - -
- -
-
- -} - -export default OrderScreen; \ No newline at end of file diff --git a/frontend/src/screens/OrdersScreen.js b/frontend/src/screens/OrdersScreen.js deleted file mode 100644 index 0af85b9..0000000 --- a/frontend/src/screens/OrdersScreen.js +++ /dev/null @@ -1,69 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { Link } from 'react-router-dom'; -import { useSelector, useDispatch } from 'react-redux'; -import { listOrders, deleteOrder } from '../actions/orderActions'; - -function OrdersScreen(props) { - const orderList = useSelector(state => state.orderList); - const { loading, orders, error } = orderList; - - const orderDelete = useSelector(state => state.orderDelete); - const { loading: loadingDelete, success: successDelete, error: errorDelete } = orderDelete; - - const dispatch = useDispatch(); - - useEffect(() => { - dispatch(listOrders()); - return () => { - // - }; - }, [successDelete]); - - const deleteHandler = (order) => { - dispatch(deleteOrder(order._id)); - } - return loading ?
Loading...
: -
- -
-

Orders

-
-
- - - - - - - - - - - - - - - - - {orders.map(order => ( - - - - - - - - - - ))} - -
IDDATETOTALUSERPAIDPAID ATDELIVEREDDELIVERED ATACTIONS
{order._id}{order.createdAt}{order.totalPrice}{order.user.name}{order.isPaid.toString()}{order.paidAt}{order.isDelivered.toString()}{order.deliveredAt} - Details - {' '} - -
- -
-
-} -export default OrdersScreen; \ No newline at end of file diff --git a/frontend/src/screens/PaymentScreen.js b/frontend/src/screens/PaymentScreen.js deleted file mode 100644 index 3125b62..0000000 --- a/frontend/src/screens/PaymentScreen.js +++ /dev/null @@ -1,51 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { Link } from 'react-router-dom'; -import { useSelector, useDispatch } from 'react-redux'; -import { savePayment } from '../actions/cartActions'; -import CheckoutSteps from '../components/CheckoutSteps'; - -function PaymentScreen(props) { - const [paymentMethod, setPaymentMethod] = useState(''); - - const dispatch = useDispatch(); - - const submitHandler = (e) => { - e.preventDefault(); - dispatch(savePayment({ paymentMethod })); - props.history.push('placeorder'); - }; - return ( -
- -
-
-
    -
  • -

    Payment

    -
  • - -
  • -
    - setPaymentMethod(e.target.value)} - > - -
    -
  • - -
  • - -
  • -
-
-
-
- ); -} -export default PaymentScreen; diff --git a/frontend/src/screens/PlaceOrderScreen.js b/frontend/src/screens/PlaceOrderScreen.js deleted file mode 100644 index d6dedb3..0000000 --- a/frontend/src/screens/PlaceOrderScreen.js +++ /dev/null @@ -1,136 +0,0 @@ -import React, { useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { Link } from 'react-router-dom'; -import CheckoutSteps from '../components/CheckoutSteps'; -import { createOrder } from '../actions/orderActions'; -function PlaceOrderScreen(props) { - - const cart = useSelector(state => state.cart); - const orderCreate = useSelector(state => state.orderCreate); - const { loading, success, error, order } = orderCreate; - - const { cartItems, shipping, payment } = cart; - if (!shipping.address) { - props.history.push("/shipping"); - } else if (!payment.paymentMethod) { - props.history.push("/payment"); - } - const itemsPrice = cartItems.reduce((a, c) => a + c.price * c.qty, 0); - const shippingPrice = itemsPrice > 100 ? 0 : 10; - const taxPrice = 0.15 * itemsPrice; - const totalPrice = itemsPrice + shippingPrice + taxPrice; - - const dispatch = useDispatch(); - - const placeOrderHandler = () => { - // create an order - dispatch(createOrder({ - orderItems: cartItems, shipping, payment, itemsPrice, shippingPrice, - taxPrice, totalPrice - })); - } - useEffect(() => { - if (success) { - props.history.push("/order/" + order._id); - } - - }, [success]); - - return
- -
-
-
-

- Shipping -

-
- {cart.shipping.address}, {cart.shipping.city}, - {cart.shipping.postalCode}, {cart.shipping.country}, -
-
-
-

Payment

-
- Payment Method: {cart.payment.paymentMethod} -
-
-
-
    -
  • -

    - Shopping Cart -

    -
    - Price -
    -
  • - { - cartItems.length === 0 ? -
    - Cart is empty -
    - : - cartItems.map(item => -
  • -
    - product -
    -
    -
    - - {item.name} - - -
    -
    - Qty: {item.qty} -
    -
    -
    - ${item.price} -
    -
  • - ) - } -
-
- - -
-
-
    -
  • - -
  • -
  • -

    Order Summary

    -
  • -
  • -
    Items
    -
    ${itemsPrice}
    -
  • -
  • -
    Shipping
    -
    ${shippingPrice}
    -
  • -
  • -
    Tax
    -
    ${taxPrice}
    -
  • -
  • -
    Order Total
    -
    ${totalPrice}
    -
  • -
- - - -
- -
-
- -} - -export default PlaceOrderScreen; \ No newline at end of file diff --git a/frontend/src/screens/ProductScreen.js b/frontend/src/screens/ProductScreen.js deleted file mode 100644 index d0f4ec6..0000000 --- a/frontend/src/screens/ProductScreen.js +++ /dev/null @@ -1,181 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { Link } from 'react-router-dom'; -import { useSelector, useDispatch } from 'react-redux'; -import { detailsProduct, saveProductReview } from '../actions/productActions'; -import Rating from '../components/Rating'; -import { PRODUCT_REVIEW_SAVE_RESET } from '../constants/productConstants'; - -function ProductScreen(props) { - const [qty, setQty] = useState(1); - const [rating, setRating] = useState(0); - const [comment, setComment] = useState(''); - const userSignin = useSelector((state) => state.userSignin); - const { userInfo } = userSignin; - const productDetails = useSelector((state) => state.productDetails); - const { product, loading, error } = productDetails; - const productReviewSave = useSelector((state) => state.productReviewSave); - const { success: productSaveSuccess } = productReviewSave; - const dispatch = useDispatch(); - - useEffect(() => { - if (productSaveSuccess) { - alert('Review submitted successfully.'); - setRating(0); - setComment(''); - dispatch({ type: PRODUCT_REVIEW_SAVE_RESET }); - } - dispatch(detailsProduct(props.match.params.id)); - return () => { - // - }; - }, [productSaveSuccess]); - const submitHandler = (e) => { - e.preventDefault(); - // dispatch actions - dispatch( - saveProductReview(props.match.params.id, { - name: userInfo.name, - rating: rating, - comment: comment, - }) - ); - }; - const handleAddToCart = () => { - props.history.push('/cart/' + props.match.params.id + '?qty=' + qty); - }; - - return ( -
-
- Back to result -
- {loading ? ( -
Loading...
- ) : error ? ( -
{error}
- ) : ( - <> -
-
- product -
-
-
    -
  • -

    {product.name}

    -
  • -
  • - - - -
  • -
  • - Price: ${product.price} -
  • -
  • - Description: -
    {product.description}
    -
  • -
-
-
-
    -
  • Price: {product.price}
  • -
  • - Status:{' '} - {product.countInStock > 0 ? 'In Stock' : 'Unavailable.'} -
  • -
  • - Qty:{' '} - -
  • -
  • - {product.countInStock > 0 && ( - - )} -
  • -
-
-
-
-

Reviews

- {!product.reviews.length &&
There is no review
} - -
- - )} -
- ); -} -export default ProductScreen; diff --git a/frontend/src/screens/ProductsScreen.js b/frontend/src/screens/ProductsScreen.js deleted file mode 100644 index 79a3649..0000000 --- a/frontend/src/screens/ProductsScreen.js +++ /dev/null @@ -1,247 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; -import axios from 'axios'; -import { - saveProduct, - listProducts, - deleteProdcut, -} from '../actions/productActions'; - -function ProductsScreen(props) { - const [modalVisible, setModalVisible] = useState(false); - const [id, setId] = useState(''); - const [name, setName] = useState(''); - const [price, setPrice] = useState(''); - const [image, setImage] = useState(''); - const [brand, setBrand] = useState(''); - const [category, setCategory] = useState(''); - const [countInStock, setCountInStock] = useState(''); - const [description, setDescription] = useState(''); - const [uploading, setUploading] = useState(false); - const productList = useSelector((state) => state.productList); - const { loading, products, error } = productList; - - const productSave = useSelector((state) => state.productSave); - const { - loading: loadingSave, - success: successSave, - error: errorSave, - } = productSave; - - const productDelete = useSelector((state) => state.productDelete); - const { - loading: loadingDelete, - success: successDelete, - error: errorDelete, - } = productDelete; - const dispatch = useDispatch(); - - useEffect(() => { - if (successSave) { - setModalVisible(false); - } - dispatch(listProducts()); - return () => { - // - }; - }, [successSave, successDelete]); - - const openModal = (product) => { - setModalVisible(true); - setId(product._id); - setName(product.name); - setPrice(product.price); - setDescription(product.description); - setImage(product.image); - setBrand(product.brand); - setCategory(product.category); - setCountInStock(product.countInStock); - }; - const submitHandler = (e) => { - e.preventDefault(); - dispatch( - saveProduct({ - _id: id, - name, - price, - image, - brand, - category, - countInStock, - description, - }) - ); - }; - const deleteHandler = (product) => { - dispatch(deleteProdcut(product._id)); - }; - const uploadFileHandler = (e) => { - const file = e.target.files[0]; - const bodyFormData = new FormData(); - bodyFormData.append('image', file); - setUploading(true); - axios - .post('/api/uploads', bodyFormData, { - headers: { - 'Content-Type': 'multipart/form-data', - }, - }) - .then((response) => { - setImage(response.data); - setUploading(false); - }) - .catch((err) => { - console.log(err); - setUploading(false); - }); - }; - return ( -
-
-

Products

- -
- {modalVisible && ( -
-
-
    -
  • -

    Create Product

    -
  • -
  • - {loadingSave &&
    Loading...
    } - {errorSave &&
    {errorSave}
    } -
  • - -
  • - - setName(e.target.value)} - > -
  • -
  • - - setPrice(e.target.value)} - > -
  • -
  • - - setImage(e.target.value)} - > - - {uploading &&
    Uploading...
    } -
  • -
  • - - setBrand(e.target.value)} - > -
  • -
  • - - setCountInStock(e.target.value)} - > -
  • -
  • - - setCategory(e.target.value)} - > -
  • -
  • - - -
  • -
  • - -
  • -
  • - -
  • -
-
-
- )} - -
- - - - - - - - - - - - - {products.map((product) => ( - - - - - - - - - ))} - -
IDNamePriceCategoryBrandAction
{product._id}{product.name}{product.price}{product.category}{product.brand} - {' '} - -
-
-
- ); -} -export default ProductsScreen; diff --git a/frontend/src/screens/ProfileScreen.js b/frontend/src/screens/ProfileScreen.js deleted file mode 100644 index abb34de..0000000 --- a/frontend/src/screens/ProfileScreen.js +++ /dev/null @@ -1,116 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { Link } from 'react-router-dom'; -import { logout, update } from '../actions/userActions'; -import { listMyOrders } from '../actions/orderActions'; -import { useDispatch, useSelector } from 'react-redux'; - -function ProfileScreen(props) { - const [name, setName] = useState(''); - const [password, setPassword] = useState(''); - const [email, setEmail] = useState(''); - const dispatch = useDispatch(); - - const userSignin = useSelector(state => state.userSignin); - const { userInfo } = userSignin; - const handleLogout = () => { - dispatch(logout()); - props.history.push("/signin"); - } - const submitHandler = (e) => { - e.preventDefault(); - dispatch(update({ userId: userInfo._id, email, name, password })) - } - const userUpdate = useSelector(state => state.userUpdate); - const { loading, success, error } = userUpdate; - - const myOrderList = useSelector(state => state.myOrderList); - const { loading: loadingOrders, orders, error: errorOrders } = myOrderList; - useEffect(() => { - if (userInfo) { - console.log(userInfo.name) - setEmail(userInfo.email); - setName(userInfo.name); - setPassword(userInfo.password); - } - dispatch(listMyOrders()); - return () => { - - }; - }, [userInfo]) - - return
-
-
-
-
    -
  • -

    User Profile

    -
  • -
  • - {loading &&
    Loading...
    } - {error &&
    {error}
    } - {success &&
    Profile Saved Successfully.
    } -
  • -
  • - - setName(e.target.value)}> - -
  • -
  • - - setEmail(e.target.value)}> - -
  • -
  • - - setPassword(e.target.value)}> - -
  • - -
  • - -
  • -
  • - -
  • - -
-
-
-
-
- { - loadingOrders ?
Loading...
: - errorOrders ?
{errorOrders}
: - - - - - - - - - - - - {orders.map(order => - - - - - - )} - -
IDDATETOTALPAIDACTIONS
{order._id}{order.createdAt}{order.totalPrice}{order.isPaid} - DETAILS -
- } -
-
-} - -export default ProfileScreen; \ No newline at end of file diff --git a/frontend/src/screens/RegisterScreen.js b/frontend/src/screens/RegisterScreen.js deleted file mode 100644 index 8703d36..0000000 --- a/frontend/src/screens/RegisterScreen.js +++ /dev/null @@ -1,77 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { Link } from 'react-router-dom'; -import { useSelector, useDispatch } from 'react-redux'; -import { register } from '../actions/userActions'; - -function RegisterScreen(props) { - - const [name, setName] = useState(''); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [rePassword, setRePassword] = useState(''); - const userRegister = useSelector(state => state.userRegister); - const { loading, userInfo, error } = userRegister; - const dispatch = useDispatch(); - - const redirect = props.location.search ? props.location.search.split("=")[1] : '/'; - useEffect(() => { - if (userInfo) { - props.history.push(redirect); - } - return () => { - // - }; - }, [userInfo]); - - const submitHandler = (e) => { - e.preventDefault(); - dispatch(register(name, email, password)); - } - return
-
- -
-
-} -export default RegisterScreen; \ No newline at end of file diff --git a/frontend/src/screens/ShippingScreen.js b/frontend/src/screens/ShippingScreen.js deleted file mode 100644 index c2a304e..0000000 --- a/frontend/src/screens/ShippingScreen.js +++ /dev/null @@ -1,70 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { Link } from 'react-router-dom'; -import { useSelector, useDispatch } from 'react-redux'; -import { saveShipping } from '../actions/cartActions'; -import CheckoutSteps from '../components/CheckoutSteps'; - -function ShippingScreen(props) { - - const [address, setAddress] = useState(''); - const [city, setCity] = useState(''); - const [postalCode, setPostalCode] = useState(''); - const [country, setCountry] = useState(''); - - const dispatch = useDispatch(); - - const submitHandler = (e) => { - e.preventDefault(); - dispatch(saveShipping({ address, city, postalCode, country })); - props.history.push('payment'); - } - return
- -
-
-
    -
  • -

    Shipping

    -
  • - -
  • - - setAddress(e.target.value)}> - -
  • -
  • - - setCity(e.target.value)}> - -
  • -
  • - - setPostalCode(e.target.value)}> - -
  • -
  • - - setCountry(e.target.value)}> - -
  • - - -
  • - -
  • - -
-
-
-
- -} -export default ShippingScreen; \ No newline at end of file diff --git a/frontend/src/screens/SigninScreen.js b/frontend/src/screens/SigninScreen.js deleted file mode 100644 index e93e83c..0000000 --- a/frontend/src/screens/SigninScreen.js +++ /dev/null @@ -1,63 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { Link } from 'react-router-dom'; -import { useSelector, useDispatch } from 'react-redux'; -import { signin } from '../actions/userActions'; - -function SigninScreen(props) { - - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const userSignin = useSelector(state => state.userSignin); - const { loading, userInfo, error } = userSignin; - const dispatch = useDispatch(); - const redirect = props.location.search ? props.location.search.split("=")[1] : '/'; - useEffect(() => { - if (userInfo) { - props.history.push(redirect); - } - return () => { - // - }; - }, [userInfo]); - - const submitHandler = (e) => { - e.preventDefault(); - dispatch(signin(email, password)); - - } - return
-
- -
-
-} -export default SigninScreen; \ No newline at end of file diff --git a/manifest.yml b/manifest.yml new file mode 100644 index 0000000..52a2c22 --- /dev/null +++ b/manifest.yml @@ -0,0 +1,11 @@ +applications: + - name: call-for-code-2021 + path: . + command: node server.js + instances: 1 + routes: + - route: maratona-cf-exemplo.mybluemix.net + random-route: true + memory: 128M + env: + PORT: 3000 diff --git a/package.json b/package.json index e3ac4b6..fdcd256 100644 --- a/package.json +++ b/package.json @@ -1,48 +1,43 @@ { - "name": "amazona", - "version": "1.0.0", - "description": "Demo : https://amazonaapp.herokuapp.com/", - "main": "index.js", + "name": "frontend", + "proxy": "http://127.0.0.1:5000", + "version": "0.1.0", + "private": true, "dependencies": { - "aws-sdk": "^2.702.0", - "body-parser": "^1.19.0", - "dotenv": "^8.2.0", - "eslint-plugin-react": "^7.19.0", + "@testing-library/jest-dom": "^4.2.4", + "@testing-library/react": "^9.3.2", + "@testing-library/user-event": "^7.1.2", + "axios": "^0.19.2", "express": "^4.17.1", - "jsonwebtoken": "^8.5.1", - "mongoose": "^5.8.11", - "multer": "^1.4.2", - "multer-s3": "^2.9.0" - }, - "devDependencies": { - "@babel/cli": "^7.8.4", - "@babel/core": "^7.8.4", - "@babel/node": "^7.8.4", - "@babel/preset-env": "^7.8.4", - "eslint": "^6.8.0", - "eslint-config-airbnb": "^18.1.0", - "eslint-plugin-import": "^2.20.1", - "eslint-plugin-jsx-a11y": "^6.2.3", - "eslint-plugin-react-hooks": "^2.5.1", - "nodemon": "^2.0.2" + "js-cookie": "^2.2.1", + "react": "^16.12.0", + "react-dom": "^16.12.0", + "react-html-parser": "^2.0.2", + "react-redux": "^7.1.3", + "react-router-dom": "^5.1.2", + "react-scripts": "^3.4.1", + "redux": "^4.0.5", + "redux-thunk": "^2.3.0" }, "scripts": { - "start": "nodemon --watch backend --exec babel-node backend/server.js", - "build": "rm -rf dist && babel backend -d dist && cd frontend && npm install && npm run build", - "heroku-postbuild-x": "npm run build && cd frontend && npm install && npm run build" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/basir/amazona.git" + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" }, - "author": "", - "license": "ISC", - "bugs": { - "url": "https://github.com/basir/amazona/issues" + "eslintConfig": { + "extends": "react-app" }, - "homepage": "https://github.com/basir/amazona#readme", - "engines": { - "node": "12.4.0", - "npm": "6.9.0" + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] } } diff --git a/public/favicon-eco.png b/public/favicon-eco.png new file mode 100644 index 0000000..3adb6a3 Binary files /dev/null and b/public/favicon-eco.png differ diff --git a/frontend/public/images/d1.jpg b/public/images/d1.jpg similarity index 100% rename from frontend/public/images/d1.jpg rename to public/images/d1.jpg diff --git a/frontend/public/images/d2.jpg b/public/images/d2.jpg similarity index 100% rename from frontend/public/images/d2.jpg rename to public/images/d2.jpg diff --git a/frontend/public/images/d3.jpg b/public/images/d3.jpg similarity index 100% rename from frontend/public/images/d3.jpg rename to public/images/d3.jpg diff --git a/frontend/public/images/p1.jpg b/public/images/p1.jpg similarity index 100% rename from frontend/public/images/p1.jpg rename to public/images/p1.jpg diff --git a/frontend/public/images/p2.jpg b/public/images/p2.jpg similarity index 100% rename from frontend/public/images/p2.jpg rename to public/images/p2.jpg diff --git a/frontend/public/images/p3.jpg b/public/images/p3.jpg similarity index 100% rename from frontend/public/images/p3.jpg rename to public/images/p3.jpg diff --git a/frontend/public/index.html b/public/index.html similarity index 71% rename from frontend/public/index.html rename to public/index.html index 47b095d..5205a7a 100644 --- a/frontend/public/index.html +++ b/public/index.html @@ -2,14 +2,21 @@ - + - + + + + + + + +