├── .gitignore ├── README.md ├── notes todo.txt ├── package-lock.json ├── package.json ├── public ├── SHIQA.png ├── ico.png ├── index.html ├── manifest.json └── robots.txt └── src ├── SHIQA.png ├── components ├── Alert │ └── Index.js ├── Auth │ ├── Login.js │ ├── Scss │ │ └── Index.scss │ └── SignUp.js ├── Category │ ├── Add.js │ ├── Index.js │ ├── List.js │ └── scss │ │ └── index.scss ├── Edit │ ├── CategoryDropdown.js │ ├── Index.js │ ├── PriceSettings.js │ ├── SegmentsDropdown.js │ ├── UpdateVariationOptions.js │ ├── UpdateVariations.js │ └── scss │ │ └── index.scss ├── Filter │ └── Filter.js ├── Header │ ├── Index.js │ └── Sass │ │ └── Style.scss ├── Helpers │ └── functions.js ├── Hero │ ├── Index.js │ └── Sass │ │ └── Style.scss ├── Order │ ├── Index.js │ ├── Product.js │ ├── Sass │ │ └── Index.scss │ └── ViewOrder.js ├── Product │ ├── AddProducts.js │ ├── Product.js │ ├── Products.js │ └── Sass │ │ └── Style.scss ├── Segments │ ├── Add.js │ ├── Index.js │ └── List.js ├── Update │ ├── Index.js │ ├── Product.js │ └── Sass │ │ └── Index.scss ├── Uploads │ ├── AddVariationOptions.js │ ├── AddVariations.js │ ├── CategoryDropdown.js │ ├── Index.js │ ├── PriceSettings.js │ ├── SegmentsDropdown.js │ └── scss │ │ └── index.scss └── WishList │ ├── Index.js │ ├── Product.js │ └── Sass │ └── Index.scss ├── config └── firebase.js ├── containers ├── Admin.js ├── Filters.js ├── Home.js └── Shop.js ├── contexts ├── AuthContext.js ├── ProductContext.js └── WishListContext.js ├── index.js ├── layouts └── Sidebar.js ├── logo.svg ├── reducers ├── AuthReducer.js ├── ProductReducer.js └── WishListReducer.js ├── redux ├── actions │ └── order │ │ ├── orderActions.js │ │ └── orderTypes.js ├── reducers │ ├── orderReducer.js │ └── rootReducer.js └── store.js ├── serviceWorker.js ├── styles ├── global.scss ├── mixins.scss ├── reset.scss └── variables.scss └── utils └── Index.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project can be viewed in https://admin-shiqa.netlify.com/. 2 | 3 | ## Admin Shiqa Ecommerce App 4 | 5 | This app is the admin part of Shiqa Shopping ecommerce app, where we can process clients orders, aproved orders, update quantity, update prices, add and remove products, add shipping fee based on orders, upload product images, add and remove categories & segments and many more. 6 | 7 | This app this built in React Js, Redux, Redux-thunk, React-Bootstrap and Firebase BackEnd. 8 | 9 | The client side of this app is a mobile android app which is built in react native, redux, redux-thunk and firebase. Please download the client android app here: https://drive.google.com/file/d/1uW8-p-ovmO2MEgxw1Zz3AcBXTRW9oVWU/view?usp=sharing 10 | 11 | 12 | For testing you can use this temporary user: 13 | 14 | email: test@gmail.com 15 | password: testing 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /notes todo.txt: -------------------------------------------------------------------------------- 1 | 2. process orders 2 | 3. products filter by name for products edits and updates 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-shop", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@fortawesome/fontawesome-svg-core": "^1.2.27", 7 | "@fortawesome/free-solid-svg-icons": "^5.12.1", 8 | "@fortawesome/react-fontawesome": "^0.1.8", 9 | "animate.css": "^3.7.2", 10 | "bootstrap": "^4.4.1", 11 | "firebase": "^7.2.0", 12 | "grpc": "^1.24.2", 13 | "node-sass": "^4.13.1", 14 | "react": "^16.12.0", 15 | "react-bootstrap": "^1.0.0-beta.16", 16 | "react-dom": "^16.12.0", 17 | "react-firebase-file-uploader": "^2.4.3", 18 | "react-input-switch": "^2.2.1", 19 | "react-loader-spinner": "^3.1.5", 20 | "react-notifications-component": "^2.3.0", 21 | "react-redux": "^7.2.0", 22 | "react-router-dom": "^5.1.2", 23 | "react-scripts": "^3.4.0", 24 | "react-uuid": "^1.0.2", 25 | "reactjs-popup": "^1.5.0", 26 | "redux": "^4.0.5", 27 | "redux-devtools-extension": "^2.13.8", 28 | "redux-thunk": "^2.3.0", 29 | "styled-components": "^4.4.1" 30 | }, 31 | "scripts": { 32 | "start": "react-scripts start", 33 | "build": "react-scripts build", 34 | "test": "react-scripts test", 35 | "eject": "react-scripts eject" 36 | }, 37 | "eslintConfig": { 38 | "extends": "react-app" 39 | }, 40 | "browserslist": { 41 | "production": [ 42 | ">0.2%", 43 | "not dead", 44 | "not op_mini all" 45 | ], 46 | "development": [ 47 | "last 1 chrome version", 48 | "last 1 firefox version", 49 | "last 1 safari version" 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /public/SHIQA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/talljohnthin/react-shop/4dac27b84ff4ff48b5d6d0530a3de897702e087c/public/SHIQA.png -------------------------------------------------------------------------------- /public/ico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/talljohnthin/react-shop/4dac27b84ff4ff48b5d6d0530a3de897702e087c/public/ico.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 19 | 20 | 29 | Shiqa Shopping 30 | 31 | 32 | 33 | 34 |
35 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | // { 6 | // "src": "favicon.ico", 7 | // "sizes": "64x64 32x32 24x24 16x16", 8 | // "type": "image/x-icon" 9 | // }, 10 | // { 11 | // "src": "logo192.png", 12 | // "type": "image/png", 13 | // "sizes": "192x192" 14 | // }, 15 | // { 16 | // "src": "logo512.png", 17 | // "type": "image/png", 18 | // "sizes": "512x512" 19 | // } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /src/SHIQA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/talljohnthin/react-shop/4dac27b84ff4ff48b5d6d0530a3de897702e087c/src/SHIQA.png -------------------------------------------------------------------------------- /src/components/Alert/Index.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react' 2 | import { Alert } from 'react-bootstrap' 3 | export default function Index(props) { 4 | const { showAlert, message, type } = props 5 | const alertStyle = { 6 | position: 'fixed', 7 | top: showAlert ? '0' : '-100%', 8 | left: '50%', 9 | transform: 'translateX(-50%)', 10 | transition: 'all ease 0.25s', 11 | zIndex:'9999', 12 | width:'300px', 13 | borderRadius:0 14 | } 15 | 16 | return ( 17 | 18 | 19 | { message } 20 | 21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /src/components/Auth/Login.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useContext, useState, useEffect } from 'react' 2 | import { Container, Card } from 'react-bootstrap' 3 | import firebase from '../../config/firebase' 4 | import { Redirect } from "react-router-dom"; 5 | import { AuthContext } from '../../contexts/AuthContext' 6 | import './Scss/Index.scss' 7 | 8 | const Login = () => { 9 | 10 | const [email, setEmail] = useState('') 11 | const [password, setPassword] = useState('') 12 | const [redirect, setRedirect] = useState(false) 13 | const [errorMessage, setErrorMessage] = useState('') 14 | const [successMessage, setSuccessMessage] = useState('') 15 | const [isLoading, setIsLoading] = useState(false) 16 | const { state, dispatch } = useContext(AuthContext) 17 | 18 | if (redirect) { 19 | return 20 | } 21 | 22 | const handleLogin = async(e) => { 23 | e.preventDefault() 24 | setIsLoading(true) 25 | if ( email === '' || password === '') { 26 | setErrorMessage('Email and Password cannot be empty.') 27 | setIsLoading(false) 28 | return 29 | } 30 | const user = await firebase.auth().signInWithEmailAndPassword(email, password).catch( err => { 31 | setIsLoading(false) 32 | setErrorMessage(err.message) 33 | return null 34 | }) 35 | if ( user ) { 36 | dispatch({ 37 | type: "LOGIN", 38 | payload: user 39 | }) 40 | setIsLoading(false) 41 | setErrorMessage('') 42 | setSuccessMessage('Login Successfully!') 43 | setTimeout(()=>{ 44 | setRedirect(true) 45 | },400) 46 | } 47 | } 48 | 49 | return ( 50 | 51 | 52 | 53 | 54 |
Admin User Login
55 |
56 | 57 |
58 |
59 | { 60 | successMessage && (
{successMessage}
) 61 | } 62 | { 63 | isLoading ? (
Please wait...
) : 64 | errorMessage && (
{errorMessage}
) 65 | } 66 | 67 | setEmail(e.currentTarget.value)} /> 68 | 69 | setPassword(e.currentTarget.value)} /> 70 | 71 | {/* */} 72 |
73 |
74 |
75 |
76 |
77 |
78 | ) 79 | } 80 | 81 | 82 | export default Login 83 | -------------------------------------------------------------------------------- /src/components/Auth/Scss/Index.scss: -------------------------------------------------------------------------------- 1 | .login-container { 2 | max-width:380px; 3 | margin:0 auto; 4 | padding:40px 20px; 5 | ._loading_overlay_wrapper { 6 | background:rgba(0,0,0, 0.4); 7 | 8 | } 9 | label { 10 | margin-bottom:5px; 11 | } 12 | input { 13 | margin-bottom:15px; 14 | } 15 | .btn-primary { 16 | float:right; 17 | width:100%; 18 | display: block; 19 | } 20 | .alert { 21 | display: block; 22 | width:100%; 23 | } 24 | } -------------------------------------------------------------------------------- /src/components/Auth/SignUp.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useContext, useState } from 'react' 2 | import { Container, Card } from 'react-bootstrap' 3 | import firebase from '../../config/firebase' 4 | import { Redirect } from "react-router-dom"; 5 | 6 | const SignUp = () => { 7 | 8 | const [email, setEmail] = useState('') 9 | const [password, setPassword] = useState('') 10 | const [name, setName] = useState('') 11 | const [phone, setPhone] = useState('') 12 | const [redirect, setRedirect] = useState(false) 13 | const [errorMessage, setErrorMessage] = useState('') 14 | const [successMessage, setSuccessMessage] = useState('') 15 | const [isLoading, setIsLoading] = useState(false) 16 | 17 | if (redirect) { 18 | return 19 | } 20 | 21 | const handleSignUp = (e) => { 22 | e.preventDefault() 23 | 24 | if( email && password) { 25 | setIsLoading(true) 26 | firebase.auth().createUserWithEmailAndPassword(email,password) 27 | .then((result) => { 28 | setPassword('') 29 | setEmail('') 30 | return result.user.updateProfile({ 31 | displayName: name, 32 | phoneNumber: phone 33 | }).then(() => { 34 | setName('') 35 | setPhone('') 36 | setIsLoading(false) 37 | setSuccessMessage('Signed Up Successfully') 38 | setTimeout(()=>{ 39 | setRedirect(true) 40 | },300) 41 | }) 42 | }) 43 | .catch( error => { 44 | setErrorMessage(error) 45 | setIsLoading(false) 46 | }) 47 | }else { 48 | setErrorMessage('Email & Password cannot be empty!') 49 | } 50 | } 51 | return ( 52 | 53 | 54 | 55 | 56 |
Add New Admin User
57 |
58 | 59 |
60 |
61 | { 62 | successMessage && (
{successMessage}
) 63 | } 64 | { 65 | isLoading ? (
Please wait...
) : 66 | errorMessage && (
{errorMessage}
) 67 | } 68 | 69 | setName(e.currentTarget.value)} /> 70 | 71 | setPhone(e.currentTarget.value)} /> 72 | 73 | setEmail(e.currentTarget.value)} /> 74 | 75 | setPassword(e.currentTarget.value)} placeholder="Password" /> 76 | 77 |
78 |
79 |
80 |
81 | 82 |
83 |
84 | ) 85 | } 86 | 87 | 88 | export default SignUp 89 | -------------------------------------------------------------------------------- /src/components/Category/Add.js: -------------------------------------------------------------------------------- 1 | import React, { Component, Fragment } from 'react' 2 | import firebase from 'firebase/app' 3 | import FileUploader from "react-firebase-file-uploader" 4 | import { Button, Form, Modal } from 'react-bootstrap' 5 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 6 | import { faPlus, faSave, faTimes } from '@fortawesome/free-solid-svg-icons' 7 | import './scss/index.scss' 8 | 9 | export default class Add extends Component { 10 | constructor(props) { 11 | super(props) 12 | this.state = { 13 | category: '', 14 | show:false, 15 | isUploading: false, 16 | progress: 0, 17 | imageURL: "" 18 | } 19 | } 20 | handleUpdateStateCategory = e => { 21 | e.preventDefault() 22 | this.setState({ 23 | category: e.target.value 24 | }) 25 | } 26 | handleFormSubmit = e => { 27 | e.preventDefault() 28 | this.props.handleAddNewCategory(this.state.category, this.state.imageURL) 29 | this.setState({ 30 | category:'' 31 | }) 32 | 33 | } 34 | handleClose = () => { 35 | this.setState({ 36 | show:false 37 | }) 38 | } 39 | handleShow = () => { 40 | this.setState({ 41 | show:true 42 | }) 43 | } 44 | handleUploadStart = () => this.setState({ isUploading: true, progress: 0 }); 45 | handleProgress = progress => this.setState({ progress }); 46 | handleUploadError = error => { 47 | this.setState({ isUploading: false }); 48 | console.error(error); 49 | }; 50 | handleUploadSuccess = filename => { 51 | this.setState({ progress: 100, isUploading: false }); 52 | firebase 53 | .storage() 54 | .ref("images") 55 | .child(filename) 56 | .getDownloadURL() 57 | .then(url => this.setState({ imageURL: url })); 58 | }; 59 | render() { 60 | return ( 61 | 62 | 65 | 70 |
71 | 72 | Add Category 73 | 74 | 75 | Select Category Image: 76 | {this.state.imageURL && } 77 | 88 | {this.state.isUploading &&

Progress: {this.state.progress}

} 89 | Add category name: 90 | 91 | 92 | 93 |
94 | 95 | 98 | 101 | 102 |
103 |
104 |
105 | ) 106 | } 107 | } 108 | 109 | 110 | const addButton = { 111 | marginTop:'10px', 112 | float:'right', 113 | backgroundColor:'#00807d', 114 | borderColor:'#00807d' 115 | } 116 | 117 | -------------------------------------------------------------------------------- /src/components/Category/Index.js: -------------------------------------------------------------------------------- 1 | import React, { Component, Fragment } from 'react' 2 | import { ListGroup, Card } from 'react-bootstrap' 3 | import Container from 'react-bootstrap/Container' 4 | import List from './List' 5 | import Add from './Add' 6 | import { db } from '../../config/firebase' 7 | import Hero from './../Hero/Index' 8 | import Alert from '../Alert/Index' 9 | import { Redirect } from 'react-router-dom' 10 | import { AuthContext } from './../../contexts/AuthContext' 11 | 12 | const container = { 13 | padding:30, 14 | paddingTop:0 15 | } 16 | 17 | export default class Index extends Component { 18 | state = { 19 | categories: [], 20 | alertMessage: null, 21 | showAlert: false, 22 | alertType: 'success' 23 | } 24 | alertTimeout = null 25 | 26 | componentDidMount() { 27 | db.collection("category") 28 | .onSnapshot(snapshot => { 29 | const categories = [] 30 | snapshot.forEach(doc => { 31 | const obj = { 32 | id: doc.id, 33 | name: doc.data() 34 | } 35 | categories.push(obj) 36 | }) 37 | this.setState({ categories }) 38 | }); 39 | this.setState({ isLoading: true }) 40 | db.collection("category") 41 | .onSnapshot(snapshot => { 42 | const categoryList = [] 43 | snapshot.forEach(doc => { 44 | const dataObj = { 45 | id: doc.id, 46 | name: doc.data() 47 | } 48 | categoryList.push(dataObj) 49 | 50 | }) 51 | this.setState({ 52 | categoryList, 53 | isLoading: false 54 | }) 55 | }) 56 | } 57 | handleAddNewCategory = (newCategory, categoryImage) => { 58 | if (newCategory.length > 3 && categoryImage.length) { 59 | db.collection("category").add({ 60 | name: newCategory, 61 | url:categoryImage 62 | }) 63 | .then(function (docRef) { 64 | console.log("Document written with ID: ", docRef.id); 65 | }) 66 | .catch(function (error) { 67 | console.error("Error adding document: ", error); 68 | }); 69 | const alertObj = { 70 | type: 'success', 71 | message: 'New Category Added Successfuly!' 72 | } 73 | if (this.alertTimeout) { 74 | clearTimeout(this.alertTimeout) 75 | this.setState({ 76 | showAlert: false 77 | }, () => { 78 | this.alertTimeout = setTimeout(() => { 79 | this.handleShowAlert(alertObj) 80 | }, 250) 81 | }) 82 | } else { 83 | this.handleShowAlert(alertObj) 84 | } 85 | } else { 86 | const alertObj = { 87 | type: 'failed', 88 | message: 'Character must be greater than 3 and It must have a category image' 89 | } 90 | if (this.alertTimeout) { 91 | clearTimeout(this.alertTimeout) 92 | this.setState({ 93 | showAlert: false 94 | }, () => { 95 | this.alertTimeout = setTimeout(() => { 96 | this.handleShowAlert(alertObj) 97 | }, 250) 98 | }) 99 | } else { 100 | this.handleShowAlert(alertObj) 101 | } 102 | } 103 | } 104 | handleShowAlert = ({ message, type }) => { 105 | this.setState({ 106 | showAlert: true, 107 | alertMessage: message, 108 | alertType: type 109 | }, () => { 110 | this.alertTimeout = setTimeout(() => { 111 | this.setState({ 112 | showAlert: false, 113 | }) 114 | }, 3000) 115 | }) 116 | } 117 | handleRemoveCategory = (id) => { 118 | db.collection("category").doc(id).delete().then(function () { 119 | console.log('deleted') 120 | }).catch(function (error) { 121 | console.error("Error removing document: ", error); 122 | }); 123 | const alertObj = { 124 | type: 'success', 125 | message: 'Category Deleted Successfuly!' 126 | } 127 | if (this.alertTimeout) { 128 | clearTimeout(this.alertTimeout) 129 | this.setState({ 130 | showAlert: false 131 | }, () => { 132 | this.alertTimeout = setTimeout(() => { 133 | this.handleShowAlert(alertObj) 134 | }, 250) 135 | }) 136 | } else { 137 | this.handleShowAlert(alertObj) 138 | } 139 | } 140 | 141 | render() { 142 | 143 | const isLoading = this.state.isLoading ? 144 | (
Loading Categories...
) : 145 | ( 149 | ) 150 | 151 | return ( 152 | 153 | 154 | {(value) => { 155 | if(Object.keys(value.state.user).length === 0 || value.state.user === null) { 156 | return 157 | } 158 | }} 159 | 160 | 161 | 162 | 167 | 168 | 169 |
List of Categories
170 |
171 | 172 | 173 | {isLoading} 174 | 175 | 178 | 179 |
180 |
181 |
182 | ) 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/components/Category/List.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, Component } from 'react' 2 | import { Modal , Button, ListGroup, Badge } from 'react-bootstrap' 3 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 4 | import { faTrashAlt, faTimes, faTrash } from '@fortawesome/free-solid-svg-icons' 5 | export default class List extends Component { 6 | 7 | state = { 8 | show:false, 9 | idToRemove:null 10 | } 11 | 12 | removeCategory = () => { 13 | if(this.state.idToRemove) { 14 | this.props.handleRemoveCategory(this.state.idToRemove) 15 | this.setState({ 16 | show:false 17 | }) 18 | } 19 | } 20 | handleClose = () => { 21 | this.setState({ 22 | show:false 23 | }) 24 | } 25 | handleShow(id) { 26 | this.setState({ 27 | show:true, 28 | idToRemove: id 29 | }) 30 | } 31 | render() { 32 | const list = this.props.categoryList.map((doc, index) => { 33 | return ( {index + 1} {doc.name.name} 34 | this.handleShow(doc.id)} 35 | style={{float:'right', cursor:'pointer'}}/> 36 | ) 37 | }) 38 | return ( 39 | 40 | { list != '' ? list : 'No category at this moment' } 41 | 47 | 48 | Delete Category 49 | 50 | 51 | 52 |

Are you sure you want to delete?

53 |
54 | 55 | 56 | 57 | 58 | 59 |
60 |
61 | ) 62 | } 63 | } 64 | 65 | 66 | const removeButton = { 67 | backgroundColor:'#f53d2d', 68 | borderColor:'#f53d2d' 69 | } -------------------------------------------------------------------------------- /src/components/Category/scss/index.scss: -------------------------------------------------------------------------------- 1 | .category-image { 2 | width:100%; 3 | margin-top:15px; 4 | } 5 | .category-file-uploader { 6 | margin:20px 0; 7 | } -------------------------------------------------------------------------------- /src/components/Edit/CategoryDropdown.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react' 2 | import { Form } from 'react-bootstrap' 3 | 4 | export default function CategoryDropdown(props) { 5 | const categories = props.categories 6 | const populateDropdownCategory = (categories) => { 7 | if (categories) { 8 | return categories.map(category => ) 9 | } 10 | } 11 | const addSelectedCategory = (category) => { 12 | props.handleAddSectedCategoryToState(category) 13 | } 14 | return ( 15 | 16 | 17 | Select Category: 18 | addSelectedCategory(e.target.value) } as="select"> 19 | 20 | { categories ? populateDropdownCategory(categories) : ( ) } 21 | 22 | 23 | 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /src/components/Edit/PriceSettings.js: -------------------------------------------------------------------------------- 1 | import React, {Fragment} from 'react' 2 | import {FormControl, Form} from 'react-bootstrap' 3 | 4 | export default function PriceSettings ({variationsValue, variation, variationIndex, variationOptions, setPrice, setAvailability, priceOptions}) { 5 | let mapOptions = null 6 | const handleSetPrice = (variationIndex, index, value) => { 7 | setPrice(variationIndex, index, value) 8 | } 9 | const handleSetAvailability = (variationIndex, index, value) => { 10 | setAvailability(variationIndex, index, value) 11 | } 12 | if (variationOptions && variationsValue) { 13 | 14 | mapOptions = variationOptions.map( (o,i) => { 15 | 16 | const price = priceOptions[variationIndex].options[i].price, 17 | status = priceOptions[variationIndex].options[i].is_available 18 | return ( 19 |
    20 |
  • { o.option }
  • 21 |
  • handleSetPrice(variationIndex, o.optionIndex, e.target.value)}>
  • 22 |
  • 23 | handleSetAvailability(variationIndex, o.optionIndex, e.target.value)}> 24 | 25 | 26 | 27 |
  • 28 |
29 | ) 30 | }) 31 | } 32 | return ( 33 | 34 |
35 | {variation} 36 |
37 |
    38 |
  • Option
  • 39 |
  • Selling Price
  • 40 |
  • Availabity
  • 41 |
42 | { mapOptions } 43 |
44 |
45 |
46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /src/components/Edit/SegmentsDropdown.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react' 2 | import { Form } from 'react-bootstrap' 3 | export default function SegmentDropdown(props) { 4 | const segments = props.segments 5 | const populateDropdownSegment = (segments) => { 6 | if (segments) { 7 | return segments.map(segment => ) 8 | } 9 | } 10 | const addSelectedSegment = (segment) => { 11 | props.handleAddSectedSegmentToState(segment) 12 | } 13 | return ( 14 | 15 | 16 | Select Segments: 17 | addSelectedSegment(e.target.value)} as="select"> 18 | 19 | {segments ? populateDropdownSegment(segments) : ()} 20 | 21 | 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /src/components/Edit/UpdateVariationOptions.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react' 2 | import { Button, FormControl } from 'react-bootstrap' 3 | import { FontAwesomeIcon} from '@fortawesome/react-fontawesome' 4 | import { faTrash } from '@fortawesome/free-solid-svg-icons' 5 | 6 | 7 | export default function UpdateVariationOptions(props) { 8 | return ( 9 | 10 |
Fields of options:
11 |
    12 | {props.variationOptions.map((option, index) =>
  • props.handleAddVariationOptionValue(e, index) }/> 13 | props.handleRemoveVariationOption(index) }/> 14 |
  • )} 15 |
16 | 17 |
18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /src/components/Edit/UpdateVariations.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react' 2 | import { Button, FormControl } from 'react-bootstrap' 3 | import { FontAwesomeIcon} from '@fortawesome/react-fontawesome' 4 | import { faTrash } from '@fortawesome/free-solid-svg-icons' 5 | 6 | 7 | export default function UpdateVariations(props) { 8 | return ( 9 | 10 |
Fields of variations:
11 |
    12 | {props.variations.map((variation, index) =>
  • props.handleAddVariationValue(e, index) }/> 13 | props.handleRemoveVariation(index) }/> 14 |
  • )} 15 |
16 | 17 |
18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /src/components/Edit/scss/index.scss: -------------------------------------------------------------------------------- 1 | @import './../../../styles/variables.scss'; 2 | 3 | .cards { 4 | display: flex; 5 | justify-content: space-between; 6 | flex-wrap: wrap; 7 | position: relative; 8 | & > div { 9 | width:48%; 10 | margin-bottom:25px; 11 | display: flex; 12 | align-items: center; 13 | justify-content: center; 14 | position: relative; 15 | img { 16 | width: 100%; 17 | } 18 | } 19 | .card { 20 | width:48%; 21 | margin-bottom:25px; 22 | display: flex; 23 | align-items: center; 24 | justify-content: center; 25 | position: relative; 26 | } 27 | .card-cover { 28 | position: relative; 29 | &:before { 30 | content:'Cover'; 31 | width:100%; 32 | height:100%; 33 | position: absolute; 34 | left:0; 35 | right:0; 36 | z-index: 1; 37 | background:rgba($secondary-color, 0.4); 38 | color:#fff; 39 | display: flex; 40 | font-size:18px; 41 | font-family: $secondary-font; 42 | font-weight: 100; 43 | align-items: center; 44 | justify-content: center; 45 | } 46 | } 47 | Button.card-close { 48 | width:30px; 49 | height:30px; 50 | border-radius:0; 51 | position: absolute; 52 | top:0; 53 | right:0; 54 | padding:0; 55 | font-size:14px; 56 | z-index: 3; 57 | } 58 | } 59 | 60 | // variations 61 | .variation-list { 62 | padding:0; 63 | li { 64 | display: flex; 65 | align-items: center; 66 | list-style-type: none; 67 | margin:0 0 10px; 68 | input { 69 | margin-right: 8px; 70 | } 71 | svg { 72 | cursor: pointer; 73 | } 74 | } 75 | } 76 | 77 | // Price Settings 78 | .each-variation { 79 | li { 80 | list-style-type: none; 81 | border:1px solid #efefef; 82 | flex:1; 83 | &:not(:last-child) { 84 | border-right:0; 85 | } 86 | } 87 | .each-variation-table-items { 88 | display: flex; 89 | } 90 | } 91 | 92 | // container 93 | div.add-entry-products-container { 94 | margin:0 15px !important; 95 | .btn-primary { 96 | background:$secondary-color; 97 | border:1px solid $secondary-color; 98 | display: flex; 99 | align-items:center; 100 | justify-content: center; 101 | //width:100%; 102 | &:focus { 103 | border:0; 104 | outline:0; 105 | } 106 | } 107 | .variation-title, 108 | .option-title, 109 | .price-title { 110 | @include font-size(15px, 16px, 500px, 1280px); 111 | font-family: $secondary-font; 112 | margin-bottom:8px; 113 | } 114 | .option-title, 115 | .price-title { 116 | margin-top: 10px; 117 | } 118 | // set price 119 | .each-variation { 120 | margin-bottom:15px; 121 | } 122 | .each-variation-title { 123 | text-transform: uppercase; 124 | margin-bottom: 10px; 125 | display: block; 126 | } 127 | .each-variation-table-items { 128 | li { 129 | padding:6px; 130 | display: flex; 131 | align-items: center; 132 | justify-content: center; 133 | text-align: center; 134 | } 135 | } 136 | 137 | .btn-product-save { 138 | border-color:#f53d2d; 139 | background:#f53d2d; 140 | } 141 | } 142 | 143 | // form 144 | .add-entry-form { 145 | @include font-size(15px, 16px, 500px, 1280px); 146 | font-family: $secondary-font; 147 | .form-control { 148 | @include font-size(15px, 16px, 500px, 1280px); 149 | } 150 | .form-label { 151 | margin-bottom:6px; 152 | font-family: $secondary-font; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/components/Filter/Filter.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function Filter() { 4 | return ( 5 |
6 |
Categories
7 | 14 |
15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /src/components/Header/Index.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useContext} from 'react' 2 | import firebase from '../../config/firebase' 3 | import Container from 'react-bootstrap/Container' 4 | import { Link } from 'react-router-dom' 5 | import { AuthContext } from './../../contexts/AuthContext' 6 | import { WishListContext} from './../../contexts/WishListContext' 7 | import logo from './../../SHIQA.png' 8 | import './Sass/Style.scss' 9 | 10 | const Index = () => { 11 | const {dispatch} = useContext(AuthContext) 12 | const {wishListState} = useContext(WishListContext) 13 | const handleLogout = () => { 14 | dispatch({type: "LOGOUT", payload:{}}) 15 | firebase.auth().signOut() 16 | } 17 | let wishListCount = null 18 | if ( wishListState) { 19 | wishListCount = wishListState.products.length <= 0 ? {opacity:0} : {opacity:1}; 20 | } 21 | return ( 22 | 23 |
24 | 25 |
26 | 27 |
28 |
29 | {/*
30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 |
41 | { wishListState.products.length } 42 |
43 |
44 |
45 | 49 | 50 | 51 | 52 |
2
53 |
*/} 54 |
55 | 56 | {(value) => { 57 | 58 | if ( value.state.user === null || Object.keys(value.state.user).length === 0 ) { 59 | return 60 |
Register
61 |
Login
62 |
63 | } else { 64 | return 65 | 66 | {/*
{firebase.auth().currentUser && firebase.auth().currentUser.displayName}
*/} 67 |
handleLogout()}>Logout
68 |
69 | } 70 | }} 71 |
72 |
73 |
74 |
75 |
76 |
77 | ) 78 | } 79 | 80 | export default Index; 81 | 82 | const style = { 83 | opacity: 1, 84 | vectorEffect: 'none', 85 | fill: '#000000', 86 | fillOpacity: 1 87 | } -------------------------------------------------------------------------------- /src/components/Header/Sass/Style.scss: -------------------------------------------------------------------------------- 1 | @import './../../../styles/variables.scss'; 2 | 3 | 4 | .header { 5 | background:#fff; 6 | position: fixed; 7 | top:0; 8 | left:0; 9 | width:100%; 10 | z-index: 99999; 11 | overflow: hidden; 12 | box-shadow: 0 0 10px 1px rgba(68,102,242,.05); 13 | .container { 14 | height: 64px; 15 | display: flex; 16 | font-family: 'Roboto Slab', serif; 17 | justify-content: space-between; 18 | align-items: center; 19 | } 20 | .left { 21 | .logo { 22 | max-width: 150px; 23 | } 24 | } 25 | .right { 26 | display: flex; 27 | align-items: center; 28 | .wishlist { 29 | margin-right:12px; 30 | position: relative; 31 | svg { 32 | font-size:16px; 33 | } 34 | .wishlist-count { 35 | position: absolute; 36 | top:0; 37 | right:-7px; 38 | background: $secondary-color; 39 | width:15px; 40 | height:15px; 41 | border-radius: 50%; 42 | display: flex; 43 | align-items: center; 44 | justify-content: center; 45 | font-family: $secondary-font; 46 | font-size:10px; 47 | color:#fff; 48 | pointer-events: none; 49 | } 50 | } 51 | .orders { 52 | position: relative; 53 | svg { 54 | font-size:18px; 55 | } 56 | .orders-count { 57 | position: absolute; 58 | top:0; 59 | right:-7px; 60 | background: $secondary-color; 61 | width:15px; 62 | height:15px; 63 | border-radius: 50%; 64 | display: flex; 65 | align-items: center; 66 | justify-content: center; 67 | font-family: $secondary-font; 68 | font-size:10px; 69 | color:#fff; 70 | } 71 | } 72 | .user-login { 73 | margin-left: 15px; 74 | color:#fff; 75 | display: flex; 76 | a { 77 | color:#fff; 78 | text-decoration: none; 79 | } 80 | .user-button { 81 | cursor: pointer; 82 | font-family: $secondary-font; 83 | background:$secondary-color; 84 | padding:10px 20px; 85 | border-radius: 4px; 86 | color:'#fff' !important; 87 | font-size: 15px; 88 | } 89 | } 90 | 91 | } 92 | } -------------------------------------------------------------------------------- /src/components/Helpers/functions.js: -------------------------------------------------------------------------------- 1 | import { store } from 'react-notifications-component'; 2 | 3 | const notification = (title, message, type) => { 4 | store.addNotification({ 5 | title, 6 | message, 7 | type, // 'default', 'success', 'info', 'warning' 8 | container: 'top-center', // where to position the notifications 9 | animationIn: ["animated", "fadeIn"], // animate.css classes that's applied 10 | animationOut: ["animated", "fadeOut"], // animate.css classes that's applied 11 | dismiss: { 12 | duration: 1500 13 | } 14 | }) 15 | } 16 | 17 | export default notification -------------------------------------------------------------------------------- /src/components/Hero/Index.js: -------------------------------------------------------------------------------- 1 | import React, { Component, Fragment } from 'react' 2 | import Container from 'react-bootstrap/Container' 3 | import './Sass/Style.scss' 4 | 5 | export default class Index extends Component { 6 | constructor(props) { 7 | super(props) 8 | } 9 | render() { 10 | return ( 11 | 12 |
13 | 14 |

{this.props.title}

15 |
16 |
17 |
18 | ) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/components/Hero/Sass/Style.scss: -------------------------------------------------------------------------------- 1 | @import './../../../styles/mixins.scss'; 2 | $primary-color: #F6F8FA; 3 | $secondary-color:#39A7AB; 4 | $primary-font: 'PT Sans', sans-serif; 5 | $secondary-font:'Roboto', sans-serif; 6 | 7 | .hero { 8 | height: 80px; 9 | display: flex; 10 | align-items: center; 11 | justify-content: center; 12 | width: 100%; 13 | padding:0 15px; 14 | @media (max-width:767px) { 15 | height: 60px; 16 | } 17 | h1 { 18 | text-align: left; 19 | @include font-size(19px, 19px, 500px, 1280px); 20 | font-family: $primary-font; 21 | letter-spacing: 0.5px; 22 | font-weight: 700; 23 | text-transform: uppercase; 24 | } 25 | } -------------------------------------------------------------------------------- /src/components/Order/Index.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useState, useEffect } from 'react' 2 | import { ListGroup, Form, Button, Card } from 'react-bootstrap' 3 | import Container from 'react-bootstrap/Container' 4 | import { connect } from 'react-redux' 5 | import { getOrders, getOrdersByCustomer, selectOrder } from './../../redux/actions/order/orderActions' 6 | import { formatOrderDate, Spinner } from './../../utils/Index' 7 | import { Redirect } from 'react-router-dom' 8 | import { AuthContext } from './../../contexts/AuthContext' 9 | 10 | const Index = ({ stateOrders, getOrders, getOrdersByCustomer, selectOrder }) => { 11 | let isMounted = false 12 | const [ selectionOrder, setSelectionOrder ] = useState('To Review') 13 | const [ customerId, setCustomerId ] = useState('') 14 | const [redirect, setRedirect] = useState(false) 15 | useEffect(()=>{ 16 | isMounted = true 17 | if(stateOrders.length === 0) { 18 | getOrders('On Review') 19 | } 20 | return () => { 21 | isMounted = false 22 | } 23 | }, []) 24 | 25 | const handleCheckOrder = id => { 26 | if(id) { 27 | selectOrder(id) 28 | setRedirect(true) 29 | } 30 | } 31 | 32 | if (redirect) { 33 | return 34 | } 35 | 36 | const onRadioChange = (e) => { 37 | setSelectionOrder(e.target.value) 38 | switch(e.target.value) { 39 | case 'To Review': 40 | getOrders('On Review') 41 | break; 42 | case 'To Proccess': 43 | getOrders('On Ship') 44 | break; 45 | case 'Completed': 46 | getOrders('Received') 47 | break; 48 | default: 49 | return 50 | } 51 | } 52 | 53 | const handleSearchOrderByCustomer = () => { 54 | switch(selectionOrder) { 55 | case 'To Review': 56 | getOrdersByCustomer('On Review', customerId) 57 | break; 58 | case 'To Proccess': 59 | getOrdersByCustomer('On Ship', customerId) 60 | break; 61 | case 'Completed': 62 | getOrdersByCustomer('Received', customerId) 63 | break; 64 | default: 65 | return 66 | } 67 | } 68 | 69 | const listOfOrders = stateOrders.length < 1 ? 70 |
Loading items...
: 71 | stateOrders.map((e,i) => { 72 | const orderDate = formatOrderDate(e.name.order_date) 73 | return handleCheckOrder(e.id) }> 76 | { orderDate } 77 | 78 | 79 | }) 80 | return ( 81 | 82 | 83 | {(value) => { 84 | if(Object.keys(value.state.user).length === 0 || value.state.user === null) { 85 | return 86 | } 87 | }} 88 | 89 |
90 | Search by order ID: 91 |
92 | setCustomerId(e.currentTarget.value)} /> 93 | 95 |
96 |
97 | 98 | 99 |
100 |
101 | 109 |
110 |
111 | 118 |
119 |
120 | 127 |
128 |
129 |
130 | { listOfOrders } 131 |
132 |
133 |
134 | ) 135 | } 136 | 137 | const mapStateToProps = (state) => ({ 138 | stateOrders :state.orders.orders 139 | }) 140 | 141 | const mapDispatchToProps = { getOrders, getOrdersByCustomer, selectOrder } 142 | export default connect(mapStateToProps, mapDispatchToProps)(Index) 143 | 144 | const container = { 145 | padding:30, 146 | } 147 | const formRadio = { 148 | display:'flex', 149 | justifyContent:'row', 150 | paddingBottom:15 151 | } -------------------------------------------------------------------------------- /src/components/Order/Product.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useContext, useState, useEffect } from 'react' 2 | import { formatMoney } from './../../utils/Index' 3 | import { connect } from 'react-redux' 4 | import { addQuantity, sumProductsInOrder, subtractQuantity , removeToOrder} from './../../redux/actions/order/orderActions' 5 | 6 | import './Sass/Index.scss' 7 | 8 | const Product = (props) => { 9 | const { cover, name, variation, option, qty, price, total } = props.product 10 | 11 | const handleAddQty = () => { 12 | if(props.index !== null || props.index !== undefined) { 13 | props.addQuantity(props.index) 14 | props.sumProductsInOrder() 15 | } 16 | } 17 | const handleSubtractQty = () => { 18 | if(props.index !== null || props.index !== undefined) { 19 | props.subtractQuantity(props.index) 20 | props.sumProductsInOrder() 21 | } 22 | } 23 | const handleRemove = () => { 24 | if(props.index !== null || props.index !== undefined) { 25 | props.removeToOrder(props.index) 26 | props.sumProductsInOrder() 27 | } 28 | } 29 | 30 | return ( 31 | 32 |
33 |
34 |
35 | { { } 36 |
37 |
38 |
39 | 40 |
41 | 42 |

{ name }

43 |

Variation: { variation }

44 |

Option: { option }

45 | 46 |
Qty: { qty } 47 |
48 | handleSubtractQty()}> 49 |
{ qty }
50 | handleAddQty()}> 51 |
52 |
53 |

Price:₱ { formatMoney(Number(price)) }

54 |

Total:₱ { formatMoney(Number(total)) }

55 |
56 |
57 |
58 |
59 | ) 60 | } 61 | 62 | const mapDispatchToprops = {addQuantity, sumProductsInOrder, subtractQuantity, removeToOrder} 63 | 64 | export default connect(null, mapDispatchToprops)(Product) 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/components/Order/Sass/Index.scss: -------------------------------------------------------------------------------- 1 | @import './../../../styles/variables.scss'; 2 | 3 | .WISHLIST-product { 4 | max-width:600px; 5 | margin:40px auto; 6 | } 7 | 8 | .WISHLIST-product-list .card { 9 | margin-bottom:12px; 10 | border-radius: 4px; 11 | border:0; 12 | box-shadow: 0 0.25rem 0.125rem 0 rgba(0,0,0,0.02); 13 | transition:0.3s; 14 | &:hover{ 15 | box-shadow: 0 0.25rem 0.125rem 0 rgba(0,0,0,0.06); 16 | } 17 | .card-img { 18 | border-radius: 0; 19 | } 20 | .card-total { 21 | font-weight: 700; 22 | font-family: $primary-font; 23 | font-size:14px; 24 | margin-top: 5px; 25 | margin-bottom: 5px; 26 | color:#333 !important; 27 | @media (max-width:767px) { 28 | font-size:14px; 29 | } 30 | } 31 | .card-title { 32 | color:#000; 33 | font-family: $secondary-font; 34 | font-size:15px; 35 | font-weight: 600; 36 | margin:0 0 5px; 37 | text-transform: capitalize; 38 | } 39 | .card-variation, 40 | .card-option, 41 | .card-price, 42 | .card-unit, 43 | .card-total { 44 | margin-bottom: 5px; 45 | font-size:13px; 46 | font-family: $secondary-font; 47 | display: flex; 48 | color:#343a408a; 49 | &:not(:last-child) { 50 | margin-bottom: 6px; 51 | } 52 | span { 53 | flex:1; 54 | text-transform: capitalize !important; 55 | &:first-child { 56 | max-width: 80px; 57 | text-transform: capitalize !important; 58 | 59 | } 60 | } 61 | } 62 | .card-wrapper { 63 | display: flex; 64 | align-items: center; 65 | position: relative; 66 | } 67 | .left { 68 | max-width:160px; 69 | min-height: 157px; 70 | } 71 | .right { 72 | width:100%; 73 | padding-left: 15px; 74 | padding-right: 15px; 75 | .card-units-wrapper { 76 | display: flex; 77 | align-items: center; 78 | ion-icon { 79 | width:16px; 80 | height:16px; 81 | display: flex; 82 | align-items: center; 83 | justify-content: center; 84 | background:$secondary-color; 85 | color:#fff; 86 | cursor: pointer; 87 | border-radius: 2px; 88 | } 89 | .card-units { 90 | font-size:13px; 91 | width:16px; 92 | height:16px; 93 | margin:0 3px; 94 | display: flex; 95 | align-items: center; 96 | justify-content: center; 97 | font-weight: 700; 98 | } 99 | } 100 | .card-remove { 101 | position:absolute; 102 | right:8px; 103 | top:8px; 104 | font-size: 22px !important; 105 | color:$secondary-color; 106 | cursor: pointer; 107 | } 108 | } 109 | .change-variation, 110 | .change-option { 111 | color:$secondary-color; 112 | cursor:pointer; 113 | margin-left:6px; 114 | } 115 | } 116 | 117 | .WISHLIST-product-total { 118 | background:#fff; 119 | box-shadow: 0 0.25rem 0.125rem 0 rgba(0,0,0,0.02); 120 | margin-bottom: 12px; 121 | margin-top: 20px; 122 | border-radius: 4px; 123 | overflow: hidden; 124 | .title { 125 | background:$secondary-color; 126 | color:#fff; 127 | padding: 10px 20px; 128 | font-size:16px; 129 | font-family: $secondary-font; 130 | } 131 | ul { 132 | padding:20px; 133 | li { 134 | display: flex; 135 | margin-bottom: 8px; 136 | span { 137 | flex:1; 138 | text-align: right; 139 | } 140 | input[type='number'] { 141 | max-width: 120px; 142 | border:0; 143 | border-bottom:2px solid #eee; 144 | text-align: right; 145 | -webkit-appearance: none; 146 | -moz-appearance: none; 147 | appearance: none; 148 | margin: 0; 149 | } 150 | &:first-child { 151 | .amount { 152 | font-size:16px; 153 | font-weight: 600; 154 | width: 100%; 155 | } 156 | } 157 | &:last-child { 158 | .amount { 159 | font-size:16px; 160 | text-transform: uppercase; 161 | width: 100%; 162 | max-width: 120px; 163 | font-weight: 700; 164 | } 165 | } 166 | } 167 | .label { 168 | font-size:16px; 169 | } 170 | .amount { 171 | } 172 | } 173 | } 174 | 175 | .WISHLIST-shipping-info { 176 | margin-bottom:12px; 177 | border-radius: 0; 178 | border:0; 179 | background:#fff; 180 | box-shadow: 0 0.25rem 0.125rem 0 rgba(0,0,0,0.02); 181 | .title { 182 | background:$secondary-color; 183 | color:#fff; 184 | padding: 10px 20px; 185 | font-size:14px; 186 | font-family: $secondary-font; 187 | } 188 | form { 189 | padding:20px; 190 | } 191 | .form-check { 192 | margin-bottom: 20px; 193 | input { 194 | margin-top:3px; 195 | } 196 | label { 197 | font-size:13px; 198 | font-family: $secondary-font; 199 | } 200 | } 201 | .each { 202 | margin-bottom: 8px; 203 | .label { 204 | font-size:13px; 205 | margin-bottom: 8px; 206 | } 207 | .form-group { 208 | margin:0; 209 | } 210 | .form-control { 211 | font-size: 13px; 212 | font-family: $secondary-font; 213 | border:1px solid #eee; 214 | border-radius: 0; 215 | } 216 | } 217 | } 218 | 219 | .procees-order-button { 220 | display: flex; 221 | justify-content: flex-end; 222 | button { 223 | background:$secondary-color; 224 | border-color:$secondary-color; 225 | &:hover { 226 | background-color: rgb(245, 61, 45); 227 | border-color: rgb(245, 61, 45); 228 | } 229 | } 230 | } -------------------------------------------------------------------------------- /src/components/Order/ViewOrder.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useEffect, useState } from 'react' 2 | import { connect } from 'react-redux' 3 | import Container from 'react-bootstrap/Container' 4 | import { Redirect } from 'react-router-dom' 5 | import { formatMoney } from './../../utils/Index' 6 | import Hero from './../Hero/Index' 7 | import { sumProductsInOrder, updateShippingFee, proccessOrder} from './../../redux/actions/order/orderActions' 8 | import Product from './Product' 9 | 10 | const ViewOrder = ({ selectedOrder, selectedOrderId, sumProductsInOrder, updateShippingFee, proccessOrder }) => { 11 | const order = selectedOrder 12 | const [shippingFee, setShippingFee] = useState(0) 13 | 14 | useEffect(()=>{ 15 | setShippingFee(order.name?.shipping_fee) 16 | }, []) 17 | 18 | if (!selectedOrderId) { 19 | return 20 | } 21 | const handleAddShippingFee = (e) => { 22 | if(e.target.value !== 0 || e.target.value !== null || e.target.value !== undefined) { 23 | setShippingFee(e.target.value) 24 | updateShippingFee(e.target.value) 25 | sumProductsInOrder() 26 | } 27 | } 28 | 29 | const handleProccessOrder = () => { 30 | proccessOrder(selectedOrder, selectedOrderId) 31 | } 32 | 33 | 34 | 35 | const hasOrder = () => { 36 | return order.name.products.map((product, productIndex) => { 37 | return 38 | }) 39 | } 40 | 41 | 42 | return ( 43 | 44 | 45 | 46 |
47 | { order && hasOrder() } 48 |
49 |
50 |
Total
51 |
    52 |
  • Shipping : 53 | handleAddShippingFee(e)}/> 54 |
  • 55 |
  • Total :₱ { formatMoney(order.name.total_amount) }
  • 56 |
57 |
58 |
59 | 60 |
61 |
62 |
63 | ) 64 | } 65 | 66 | const mapStateToProps = (state) => ({ 67 | selectedOrder: state.orders.selectedOrder, 68 | selectedOrderId: state.orders.selectedOrderId 69 | }) 70 | 71 | const mapDispatchToProps = { sumProductsInOrder, updateShippingFee, proccessOrder } 72 | export default connect(mapStateToProps, mapDispatchToProps)(ViewOrder) -------------------------------------------------------------------------------- /src/components/Product/AddProducts.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { db } from '../../config/firebase' 3 | 4 | export default class AddProducts extends Component { 5 | state = { 6 | category: '', 7 | description: '', 8 | images: [ 9 | { 10 | status: true, 11 | url : 'https://picsum.photos/600/400' 12 | }, 13 | { 14 | status: true, 15 | url : 'https://picsum.photos/600/400' 16 | }, 17 | { 18 | status: true, 19 | url : 'https://picsum.photos/600/400' 20 | } 21 | ] 22 | } 23 | handleChangeValue = e => { 24 | e.preventDefault() 25 | this.setState({ 26 | [e.target.name] : e.target.value 27 | }) 28 | } 29 | 30 | handleAddProducts = e => { 31 | db.collection("users").add({ 32 | first: "Johnrel", 33 | last: "Limpag", 34 | phone: '090909', 35 | role: 'user', 36 | username: 'asdf', 37 | pass:'asdf' 38 | }) 39 | .then(function(docRef) { 40 | console.log("Document written with ID: ", docRef.id); 41 | }) 42 | .catch(function(error) { 43 | console.error("Error adding document: ", error); 44 | }); 45 | 46 | } 47 | 48 | componentDidMount() { 49 | db.collection('set') 50 | .get() 51 | .then( snapshot => { 52 | const item = []; 53 | snapshot.forEach( doc => { 54 | let data = doc.data() 55 | item.push(data) 56 | }) 57 | }) 58 | .catch( error => console.log( error )) 59 | } 60 | 61 | render() { 62 | return ( 63 |
64 |
65 |
66 | 67 |
68 |
69 | 78 |
79 |
80 |