├── .gitignore ├── .vscode └── launch.json ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── screenshot ├── Icon.png ├── Screenshot_1.png ├── Screenshot_2.png ├── Screenshot_3.png └── Screenshot_4.png └── src ├── AppRouter.js ├── Components ├── Layout │ ├── CardOrder.js │ ├── CardProduct.js │ ├── DataCategory.js │ ├── DataProduct.js │ ├── ListMenu.js │ ├── MainPage.js │ ├── Message.js │ ├── Statistic.js │ └── TestPagination.js ├── Page │ ├── Dashboard.js │ ├── Login.js │ ├── Logout.js │ └── SignUp.js ├── Redux │ ├── Actions │ │ ├── auth.js │ │ ├── categories.js │ │ ├── order.js │ │ └── product.js │ ├── Reducers │ │ ├── auth.js │ │ ├── categories.js │ │ ├── index.js │ │ ├── order.js │ │ └── product.js │ └── store.js └── Styles │ ├── StyleDashboard.js │ ├── StyleDataCategory.js │ ├── StyleLogout.js │ ├── StyleMainPage.js │ ├── StyleMessage.js │ ├── StyleOrderCard.js │ ├── StyleProductCard.js │ └── StyleSignUp.js ├── index.js └── serviceWorker.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 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "chrome", 9 | "request": "launch", 10 | "name": "Launch Chrome against localhost", 11 | "url": "http://localhost:8080", 12 | "webRoot": "${workspaceFolder}" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

MSG - Mart
( React JS Point of Sales - Web App)

2 | 3 |

4 | 5 |

6 | 7 |

8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 |

MSG-Mart is an application in the form of a website and a mobile application for product management, category management and has a cashier system (point of sale), this application is made using React Js and React Native. There is only a website model in this area, if you interest and want to try the mobile app version of MSG-Mart, you can visit this link :

16 | 17 | Mobile App [MSG-Mart](https://github.com/aldoignatachandra/MSG-Mart-React_Native_POS) 18 | 19 | ## Features 20 | Product Management 21 | - Create data table 22 | - View data product 23 | - Update product 24 | - Delete product 25 | - Search product by id, name, category and Latest update 26 | - Sorting product by ascending and descending 27 | 28 | Category Management 29 | - Create data table 30 | - View data category 31 | - Update category 32 | - Delete category 33 | 34 | Transaction is Under Maintenance 35 | 36 | ## Get Started 37 | ### ( Localhost Version ) 38 | 1. Download and Install RESTfull API from [MSG-Mart API](https://github.com/aldoignatachandra/RESTful_API_Point_of_Sales_APP) 39 | 2. Run backend (API) in local with (xampp or other) 40 | 3. Git clone [MSG-Mart - React Website](https://github.com/aldoignatachandra/MSG-Mart-React_JS_POS_Redux) or download zip 41 | 4. Open in your code editor (vscode, atom or other) 42 | 5. Install node modules with type `npm install` or `yarn install` 43 | 6. Run App with type `npm start` 44 | 45 | ### ( Online Version ) 46 | 1. Prepare your internet and browser (prefer use chrome) 47 | 2. You can visit this [LINK](https://msg-mart.netlify.com/) for MSG-Mart online web app version 48 | 49 | ## Build with React Hooks & Redux 50 | 51 | 52 | ## Screenshot from the App 53 |

54 | 55 | 56 | 57 | 58 |

59 |

60 | 61 | 62 | 63 | 64 |

65 | 66 | ## License 67 | [ISC](https://en.wikipedia.org/wiki/ISC_license "ISC") 68 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fronted-pointofsales", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@material-ui/core": "^4.5.2", 7 | "@material-ui/icons": "^4.5.1", 8 | "axios": "^0.19.0", 9 | "react": "^16.11.0", 10 | "react-dom": "^16.11.0", 11 | "react-redux": "^7.1.1", 12 | "react-router-dom": "^5.1.2", 13 | "react-scripts": "3.2.0", 14 | "redux": "^4.0.4", 15 | "redux-promise-middleware": "^6.1.1" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": "react-app" 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | }, 38 | "devDependencies": { 39 | "redux-logger": "^3.0.6" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldoignatachandra/ReactJS-MsgMart/1ec8b8220a68487f2534f572d62e380efe399936/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | MSG MART 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldoignatachandra/ReactJS-MsgMart/1ec8b8220a68487f2534f572d62e380efe399936/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldoignatachandra/ReactJS-MsgMart/1ec8b8220a68487f2534f572d62e380efe399936/public/logo512.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /screenshot/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldoignatachandra/ReactJS-MsgMart/1ec8b8220a68487f2534f572d62e380efe399936/screenshot/Icon.png -------------------------------------------------------------------------------- /screenshot/Screenshot_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldoignatachandra/ReactJS-MsgMart/1ec8b8220a68487f2534f572d62e380efe399936/screenshot/Screenshot_1.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldoignatachandra/ReactJS-MsgMart/1ec8b8220a68487f2534f572d62e380efe399936/screenshot/Screenshot_2.png -------------------------------------------------------------------------------- /screenshot/Screenshot_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldoignatachandra/ReactJS-MsgMart/1ec8b8220a68487f2534f572d62e380efe399936/screenshot/Screenshot_3.png -------------------------------------------------------------------------------- /screenshot/Screenshot_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldoignatachandra/ReactJS-MsgMart/1ec8b8220a68487f2534f572d62e380efe399936/screenshot/Screenshot_4.png -------------------------------------------------------------------------------- /src/AppRouter.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BrowserRouter as Router , Redirect} from 'react-router-dom'; 3 | import { Route } from 'react-router-dom'; 4 | import { Switch } from 'react-router-dom'; 5 | 6 | //Content Import 7 | import Login from "./Components/Page/Login"; 8 | import SignUp from "./Components/Page/SignUp"; 9 | import Dashboard from "./Components/Page/Dashboard"; 10 | // import Register from './Component/Auth/Resgister'; 11 | 12 | const AppRouter = () => ( 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 |
22 |
23 | ) 24 | 25 | export default AppRouter; -------------------------------------------------------------------------------- /src/Components/Layout/CardOrder.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { withRouter } from 'react-router-dom'; 3 | import Card from '@material-ui/core/Card'; 4 | import CardContent from '@material-ui/core/CardContent'; 5 | import CardMedia from '@material-ui/core/CardMedia'; 6 | import IconButton from '@material-ui/core/IconButton'; 7 | import Typography from '@material-ui/core/Typography'; 8 | import IndeterminateCheckBoxIcon from '@material-ui/icons/IndeterminateCheckBox'; 9 | import AddBoxIcon from '@material-ui/icons/AddBox'; 10 | import { useStyles } from '../Styles/StyleOrderCard'; 11 | 12 | function CardOrder (props) { 13 | const classes = useStyles(); 14 | 15 | return ( 16 | 17 |
18 | 22 |
23 |
24 | 25 | 26 | {props.item.product_name} 27 | 28 | 29 | {props.item.price} 30 | 31 | 32 |
33 | 34 | 35 | 36 | 45 | 46 | 47 | 48 | 49 |
50 |
51 |
52 | ) 53 | } 54 | 55 | export default withRouter (CardOrder); -------------------------------------------------------------------------------- /src/Components/Layout/CardProduct.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Redirect } from 'react-router-dom'; 3 | import { useDispatch, useSelector } from 'react-redux'; 4 | import axios from 'axios'; 5 | import { useStyles } from '../Styles/StyleProductCard'; 6 | import Card from '@material-ui/core/Card'; 7 | import CardActionArea from '@material-ui/core/CardActionArea'; 8 | import CardContent from '@material-ui/core/CardContent'; 9 | import CardMedia from '@material-ui/core/CardMedia'; 10 | import Typography from '@material-ui/core/Typography'; 11 | import Divider from '@material-ui/core/Divider'; 12 | import { Grid, Button, TextField } from '@material-ui/core'; 13 | import ArrowUpwardRoundedIcon from '@material-ui/icons/ArrowUpwardRounded'; 14 | import ArrowDownwardRoundedIcon from '@material-ui/icons/ArrowDownwardRounded'; 15 | import SearchIcon from '@material-ui/icons/Search'; 16 | 17 | import { addToCart } from '../Redux/Actions/order' 18 | 19 | function ProductCard (props) { 20 | 21 | const classes = useStyles(); 22 | const [dataProduct, setDataProduct] = useState ([]); 23 | const [token, setToken] = useState (localStorage.getItem("jwt")); 24 | const [order, setOrder] = useState (''); 25 | const [sorting, setSorting] = useState ('ASC'); 26 | const [search, setSearch] = useState (""); 27 | const apiProduct = `https://pointofsalesapp.herokuapp.com/api/product`; 28 | 29 | const dispatch = useDispatch(); 30 | 31 | 32 | const fetchDataProduct = async () => { 33 | if (token === null) { 34 | return 35 | } else { 36 | const res = await axios (apiProduct,{ 37 | params: { 38 | orderBy: order, 39 | sortBy: sorting, 40 | search: search 41 | }, 42 | headers: { 43 | "x-access-token":token 44 | } 45 | }) 46 | if (res.data.status == 200) { 47 | setDataProduct (res.data.result.response); 48 | } else { 49 | setDataProduct ([]); 50 | } 51 | } 52 | } 53 | 54 | const funSearch = (e) => { 55 | e.target.name = e.target.value; 56 | setSearch (e.target.name); 57 | } 58 | 59 | const handleSearch = () => { 60 | setSearch(search); 61 | setTimeout(() => { 62 | fetchDataProduct(); 63 | }, 0); 64 | } 65 | 66 | const handleSortBy = (check) => { 67 | setSorting (check); 68 | setTimeout(() => { 69 | fetchDataProduct(); 70 | }, 0); 71 | } 72 | 73 | const handleOrderBy = (check) => { 74 | setOrder (check); 75 | setTimeout(() => { 76 | fetchDataProduct(); 77 | }, 0); 78 | } 79 | 80 | const handleAddToCart = async(selectedProduct) => { 81 | await dispatch (addToCart(selectedProduct)); 82 | } 83 | 84 | useEffect(() => { 85 | fetchDataProduct (); 86 | },[]) 87 | 88 | return ( 89 |
90 | 91 | 92 | 93 | 101 | 104 | 105 | 108 | 111 | 114 | 117 | 120 | 121 | 122 | 128 | {dataProduct.length != 0 ? 129 | dataProduct.map ((data, index) => { 130 | return ( 131 | 132 | 133 | 134 | 135 | 142 | 143 | 144 | 145 | 146 | {data.product_name} 147 | 148 | 149 | ({data.category}) 150 | 151 | 152 | Quantity : {data.quantity} 153 | 154 | 155 |

156 | 161 | 162 | Rp.{data.price} 163 | 164 | 172 | 173 |
174 | 175 |
176 |
177 | ) 178 | }) : Data Not Found} 179 |
180 |
181 | ) 182 | } 183 | 184 | export default ProductCard; -------------------------------------------------------------------------------- /src/Components/Layout/DataCategory.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Redirect ,withRouter} from 'react-router-dom'; 3 | import axios from 'axios'; 4 | import clsx from 'clsx'; 5 | import Typography from '@material-ui/core/Table'; 6 | import Table from '@material-ui/core/Table'; 7 | import TableBody from '@material-ui/core/TableBody'; 8 | import TableCell from '@material-ui/core/TableCell'; 9 | import TableHead from '@material-ui/core/TableHead'; 10 | import TableRow from '@material-ui/core/TableRow'; 11 | import DeleteIcon from '@material-ui/icons/Delete'; 12 | import EditIcon from '@material-ui/icons/Edit'; 13 | import IconButton from '@material-ui/core/IconButton'; 14 | import Paper from '@material-ui/core/Paper'; 15 | import Dialog from '@material-ui/core/Dialog'; 16 | import DialogActions from '@material-ui/core/DialogActions'; 17 | import DialogTitle from '@material-ui/core/DialogTitle'; 18 | import Button from '@material-ui/core/Button'; 19 | import TextField from '@material-ui/core/TextField'; 20 | import DialogContent from '@material-ui/core/DialogContent'; 21 | import { useStyles } from '../Styles/StyleDataCategory'; 22 | import Snackbar from '@material-ui/core/Snackbar'; 23 | import CheckCircleIcon from '@material-ui/icons/CheckCircle'; 24 | import ErrorIcon from '@material-ui/icons/Error'; 25 | import SnackbarContent from '@material-ui/core/SnackbarContent'; 26 | import TablePagination from '@material-ui/core/TablePagination'; 27 | 28 | import { connect } from 'react-redux'; 29 | import { getCategories, postCategories, patchCategories, deleteCategories } from '../Redux/Actions/categories'; 30 | 31 | const variantIcon = { 32 | success: CheckCircleIcon, 33 | error: ErrorIcon, 34 | }; 35 | 36 | function MySnackbarContentWrapper(props) { 37 | const classes = useStyles(); 38 | const { className, message, variant } = props; 39 | const Icon = variantIcon[variant]; 40 | 41 | return ( 42 | 47 | 48 | {message} 49 | 50 | } 51 | /> 52 | ); 53 | } 54 | 55 | function DataCategory (props) { 56 | const classes = useStyles(); 57 | const token = localStorage.getItem("jwt"); 58 | const [dataCategory, setDataCategory] = useState ([]); 59 | const [postDataCategory, setDataPostCategory] = useState ({name:''}); 60 | const [selectedRow, setSelectedRow] = useState ({}); 61 | 62 | const [page, setPage] = useState(0); 63 | const [infoPage, setInfoPage] = useState({maxPage: 0, totalAllCategories: 0}); 64 | const [rowsPerPage, setRowsPerPage] = useState(5); 65 | 66 | const [add, setAdd] = useState (false); 67 | const [alert, setAlert] = useState (false); 68 | const [edit, setEdit] = useState (false); 69 | const [showStatus, setShowStatus] = useState(false); 70 | const [validate, setValidate] = useState (""); 71 | const [success, setSuccess] = useState ("error") 72 | 73 | const emptyRows = rowsPerPage - Math.min(rowsPerPage, infoPage.totalAllCategories - page * rowsPerPage); 74 | 75 | const addCategory = async() => { 76 | await props.dispatch( postCategories(postDataCategory)) 77 | .then(res => { 78 | if (token === null) { 79 | console.log ("JWT Expires"); 80 | } else { 81 | if (res.value.data.status !== 400) { 82 | setShowStatus(true); 83 | setSuccess("success"); 84 | setValidate("Success Add New Category"); 85 | handleAddClose(); 86 | } else { 87 | setSuccess("error"); 88 | setShowStatus(true); 89 | setValidate(res.value.data.error); 90 | } 91 | } 92 | }) 93 | .catch((error) => setShowStatus(false)) 94 | } 95 | 96 | const deleteCategory = async() => { 97 | await props.dispatch( deleteCategories(selectedRow)) 98 | .then (res => { 99 | if (token === null) { 100 | console.log ("JWT Expires"); 101 | } else { 102 | if (res.value.data.status !== 400) { 103 | setShowStatus(true); 104 | setSuccess("success"); 105 | setValidate("Success Delete Category"); 106 | handleAlertClose(); 107 | } else { 108 | setSuccess("error"); 109 | setShowStatus(true); 110 | setValidate(res.value.data.error); 111 | } 112 | } 113 | }).catch((error) => setShowStatus(false)) 114 | } 115 | 116 | const editCategory = async() => { 117 | await props.dispatch( patchCategories(selectedRow)) 118 | .then (res => { 119 | if (token === null) { 120 | console.log ("JWT Expires"); 121 | } else { 122 | if (res.value.data.status !== 400) { 123 | setShowStatus(true); 124 | setSuccess("success"); 125 | setValidate("Success Edit Category"); 126 | handleEditClose(); 127 | } else { 128 | setSuccess("error"); 129 | setShowStatus(true); 130 | setValidate(res.value.data.error); 131 | } 132 | } 133 | }).catch((error) => setShowStatus(false)) 134 | } 135 | 136 | const fetchDataCategory = async () => { 137 | if (token === null) { 138 | return 139 | } else { 140 | await props.dispatch( getCategories(rowsPerPage, page + 1)) 141 | .then (result => { 142 | setDataCategory (result.value.data.result.response); 143 | setInfoPage (result.value.data.result.infoPage); 144 | }) 145 | .catch (error => { 146 | console.log (error); 147 | }) 148 | } 149 | } 150 | 151 | const handleChangePage = (event, newPage) => { 152 | setPage(newPage); 153 | }; 154 | 155 | const handleChangeRowsPerPage = event => { 156 | setRowsPerPage(parseInt(event.target.value, 10)); 157 | setPage(0); 158 | }; 159 | 160 | useEffect(() => { 161 | fetchDataCategory (); 162 | },[page, rowsPerPage]) 163 | 164 | const inputChangeAdd = (e) => { 165 | let newDataPost = {...postDataCategory}; 166 | newDataPost [e.currentTarget.name] = e.currentTarget.value; 167 | setDataPostCategory(newDataPost); 168 | } 169 | 170 | const inputChangeEdit = (e) => { 171 | let newDataPost = {...selectedRow}; 172 | newDataPost ["name"] = e.currentTarget.value; 173 | setSelectedRow(newDataPost); 174 | } 175 | 176 | //Handle Open Modal Add Category 177 | const handleAddOpen = () => { setAdd(true) } 178 | const handleAddClose = () => { setAdd(false) } 179 | 180 | //Handle Open Modal Edit Category 181 | const handleEditOpen = (row) => { setEdit(true); setSelectedRow (row) } 182 | const handleEditClose = () => { setEdit(false) } 183 | 184 | //Handle Open Modal Delete Category 185 | const handleAlertOpen = (row) => { setAlert(true); setSelectedRow (row) } 186 | const handleAlertClose = () => { setAlert(false) } 187 | 188 | const handleCloseSnackbar = () => { setShowStatus(false) } 189 | 190 | return ( 191 |
192 | 193 | 202 | 207 | 208 | 209 | 210 | DATA CATEGORY 211 | 212 | 215 | 216 | 217 | 218 | 219 | Name 220 | Action 221 | 222 | 223 | 224 | {props.dataCategories.map((data, index) => { 225 | return( 226 | 227 | 228 | {data.name} 229 | 230 | handleAlertOpen(data)}> 231 | 232 | 233 | || 234 | handleEditOpen(data)}> 235 | 236 | 237 | 238 | 239 | 240 | ) 241 | })} 242 | {emptyRows > 0 && ( 243 | 244 | 245 | 246 | 247 | 248 | )} 249 | 250 | 251 | 252 | 267 | 268 | 269 | 270 |
271 | 272 | {/* Modal Add Category */} 273 | 274 | Add New Category 275 | 276 | 277 | 278 | 279 | 280 | 281 | 290 | 291 | 292 |
Name 282 | 289 |
293 |
294 | 295 | 296 | 299 | 302 | 303 |
304 | 305 | {/* Modal Delete */} 306 | 307 | Are You Sure Delete This Category ? 308 | ( {selectedRow.name} ) 309 |

310 | 311 | 314 | 317 | 318 |
319 | 320 | {/* Modal Edit */} 321 | 322 | Edit Category 323 | 324 | 325 | 326 | 327 | 328 | 338 | 339 | 340 |
Name 329 | 337 |
341 |
342 | 343 | 346 | 349 | 350 | 351 |
352 |
353 |
354 | ) 355 | } 356 | 357 | const mapStateToProps = state => { 358 | return { 359 | dataCategories: state.categories.listCategory 360 | }; 361 | }; 362 | 363 | export default connect (mapStateToProps) (DataCategory); -------------------------------------------------------------------------------- /src/Components/Layout/DataProduct.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { Redirect ,withRouter } from 'react-router-dom'; 3 | import clsx from 'clsx'; 4 | import Typography from '@material-ui/core/Table'; 5 | import Avatar from '@material-ui/core/Avatar'; 6 | import Table from '@material-ui/core/Table'; 7 | import TableBody from '@material-ui/core/TableBody'; 8 | import TableCell from '@material-ui/core/TableCell'; 9 | import TableHead from '@material-ui/core/TableHead'; 10 | import TableRow from '@material-ui/core/TableRow'; 11 | import DeleteIcon from '@material-ui/icons/Delete'; 12 | import EditIcon from '@material-ui/icons/Edit'; 13 | import IconButton from '@material-ui/core/IconButton'; 14 | import Paper from '@material-ui/core/Paper'; 15 | import Dialog from '@material-ui/core/Dialog'; 16 | import DialogActions from '@material-ui/core/DialogActions'; 17 | import DialogTitle from '@material-ui/core/DialogTitle'; 18 | import Button from '@material-ui/core/Button'; 19 | import TextField from '@material-ui/core/TextField'; 20 | import DialogContent from '@material-ui/core/DialogContent'; 21 | import { useStyles } from '../Styles/StyleDataCategory'; 22 | import { MenuItem, FormControl, Select } from '@material-ui/core/'; 23 | import Snackbar from '@material-ui/core/Snackbar'; 24 | import CheckCircleIcon from '@material-ui/icons/CheckCircle'; 25 | import ErrorIcon from '@material-ui/icons/Error'; 26 | import SnackbarContent from '@material-ui/core/SnackbarContent'; 27 | import TablePagination from '@material-ui/core/TablePagination'; 28 | 29 | import { connect } from 'react-redux'; 30 | import { getProducts, deleteProducts, postProducts, patchProducts} from '../Redux/Actions/product'; 31 | import { getCategories } from '../Redux/Actions/categories'; 32 | 33 | const variantIcon = { 34 | success: CheckCircleIcon, 35 | error: ErrorIcon, 36 | }; 37 | 38 | function MySnackbarContentWrapper(props) { 39 | const classes = useStyles(); 40 | const { className, message, variant } = props; 41 | const Icon = variantIcon[variant]; 42 | 43 | return ( 44 | 49 | 50 | {message} 51 | 52 | } 53 | /> 54 | ); 55 | } 56 | 57 | function DataProduct (props) { 58 | const classes = useStyles(); 59 | const [token, setToken] = useState (localStorage.getItem("jwt")); 60 | const [dataProduct, setDataProduct] = useState ([]); 61 | const [dataCategory, setDataCategory] = useState ([]); 62 | const [postDataProduct, setPostDataProduct] = useState ({name:'', description:'',image: '', category_id:'', price:'', quantity:''}); 63 | const [selectedRow, setSelectedRow] = useState ({}); 64 | const [add, setAdd] = useState (false); 65 | const [alert, setAlert] = useState (false); 66 | const [edit, setEdit] = useState (false); 67 | const [showStatus, setShowStatus] = useState(false); 68 | const [validate, setValidate] = useState (""); 69 | const [success, setSuccess] = useState ("error") 70 | 71 | const [page, setPage] = useState(0); 72 | const [infoPage, setInfoPage] = useState({maxPage: 0, totalAllProduct: 0}); 73 | const [rowsPerPage, setRowsPerPage] = useState(5); 74 | 75 | const emptyRows = rowsPerPage - Math.min(rowsPerPage, infoPage.totalAllProduct - page * rowsPerPage); 76 | 77 | const addProduct = async() => { 78 | await props.dispatch( postProducts(postDataProduct)) 79 | .then(res => { 80 | if (token === null) { 81 | console.log ("JWT Expires"); 82 | } else { 83 | if (res.value.data.status !== 400) { 84 | setShowStatus(true); 85 | setSuccess("success"); 86 | setValidate("Success Add New Product"); 87 | handleAddClose(); 88 | } else { 89 | setSuccess("error"); 90 | setShowStatus(true); 91 | setValidate(res.value.data.error); 92 | } 93 | } 94 | }) 95 | .catch((error) => setShowStatus(false)) 96 | } 97 | 98 | const deleteProduct = async() => { 99 | await props.dispatch( deleteProducts(selectedRow)) 100 | .then (res => { 101 | if (token === null) { 102 | console.log ("JWT Expires"); 103 | } else { 104 | if (res.value.data.status !== 400) { 105 | setShowStatus(true); 106 | setSuccess("success"); 107 | setValidate("Success Delete Product"); 108 | handleAlertClose(); 109 | } else { 110 | setSuccess("error"); 111 | setShowStatus(true); 112 | setValidate(res.value.data.error); 113 | } 114 | } 115 | }).catch((error) => setShowStatus(false)) 116 | } 117 | 118 | const editProduct = async() => { 119 | await props.dispatch( patchProducts(selectedRow)) 120 | .then (res => { 121 | if (token === null) { 122 | console.log ("JWT Expires"); 123 | } else { 124 | if (res.value.data.status !== 400) { 125 | setShowStatus(true); 126 | setSuccess("success"); 127 | setValidate("Success Edit Product"); 128 | handleEditClose(); 129 | } else { 130 | setSuccess("error"); 131 | setShowStatus(true); 132 | setValidate(res.value.data.error); 133 | } 134 | } 135 | }).catch((error) => setShowStatus(false)) 136 | } 137 | 138 | const fetchDataProduct = async () => { 139 | if (token === null) { 140 | return 141 | } else { 142 | await props.dispatch( getProducts(rowsPerPage, page + 1)) 143 | .then(result => { 144 | setDataProduct (result.value.data.result.response); 145 | setInfoPage (result.value.data.result.infoPage); 146 | }) 147 | .catch(error => { 148 | console.log (error); 149 | }) 150 | } 151 | } 152 | 153 | const fetchDataCategory = async () => { 154 | if (token === null) { 155 | return 156 | } else { 157 | await props.dispatch( getCategories()) 158 | .then(res => { 159 | setDataCategory (res.value.data.result.response); 160 | }).catch(error => { 161 | console.log(error); 162 | }) 163 | } 164 | } 165 | 166 | useEffect(() => { 167 | fetchDataProduct (); 168 | fetchDataCategory (); 169 | },[page, rowsPerPage]) 170 | 171 | const handleChangePage = (event, newPage) => { 172 | setPage(newPage); 173 | }; 174 | 175 | const handleChangeRowsPerPage = event => { 176 | setRowsPerPage(parseInt(event.target.value, 10)); 177 | setPage(0); 178 | }; 179 | 180 | const inputChangeAdd = (e) => { 181 | let newDataPost = {...postDataProduct}; 182 | newDataPost [e.currentTarget.name] = e.currentTarget.value; 183 | setPostDataProduct(newDataPost); 184 | } 185 | 186 | const inputChangeEdit = (e) => { 187 | let newDataPost = {...selectedRow}; 188 | newDataPost [e.currentTarget.name] = e.currentTarget.value; 189 | setSelectedRow(newDataPost); 190 | } 191 | 192 | //Handle Category For Add Product 193 | const handleCategoryAdd = (e) => { 194 | let newDataCategory = {...postDataProduct}; 195 | newDataCategory ["category_id"] = e.target.value; 196 | setPostDataProduct(newDataCategory); 197 | } 198 | 199 | //Handle Category For Edit Product 200 | const handleCategoryEdit = (e) => { 201 | let newDataCategory = {...selectedRow}; 202 | newDataCategory.category_id = e.target.value; 203 | setSelectedRow(newDataCategory); 204 | } 205 | 206 | //Handle Open Modal Add Product 207 | const handleAddOpen = () => { setAdd(true) } 208 | const handleAddClose = () => { setAdd(false) } 209 | 210 | //Handle Open Modal Edit Product 211 | const handleEditOpen = (row) => { row.name = row.product_name; setEdit(true); setSelectedRow (row) } 212 | const handleEditClose = () => { setEdit(false) } 213 | 214 | //Handle Open Modal Delete Product 215 | const handleAlertOpen = (row) => { setAlert(true); setSelectedRow (row) } 216 | const handleAlertClose = () => { setAlert(false) } 217 | 218 | const handleCloseSnackbar = () => { setShowStatus(false) } 219 | 220 | return ( 221 |
222 | 223 | 232 | 237 | 238 | 239 | 240 | DATA PRODUCT 241 | 242 | 245 | 246 | 247 | 248 | 249 | Name 250 |  Category  251 | Description 252 | Quantity 253 | Image 254 | Price 255 | Actions 256 | 257 | 258 | {props.dataProducts.map((data, index) => { 259 | return( 260 | 261 | 262 | {data.product_name || data.name} 263 | {data.category} 264 | {data.description} 265 | {data.quantity} 266 | 267 | 268 | 269 | {data.price} 270 | 271 | handleAlertOpen(data)}> 272 | 273 | 274 | handleEditOpen(data)}> 275 | 276 | 277 | 278 | 279 | 280 | ) 281 | })} 282 | {emptyRows > 0 && ( 283 | 284 | 285 | 286 | 287 | 288 | )} 289 | 290 | 291 | 292 | 307 | 308 | 309 | 310 |
311 | 312 | {/* Modal Add Product */} 313 | 314 | Add New Product 315 | 316 | 317 | 318 | 319 | 320 | 331 | 332 | 333 | 334 | 347 | 348 | 349 | 350 | 361 | 362 | 363 | 364 | 381 | 382 | 383 | 384 | 401 | 402 | 403 | 404 | 419 | 420 | 421 |
Name 321 | 330 |
Description 335 | 346 |
Image 351 | 360 |
Price 365 | 380 |
Quantity 385 | 400 |
Category 405 | 406 | 417 | 418 |
422 |
423 | 424 | 427 | 430 | 431 |
432 | 433 | {/* Modal Delete */} 434 | 435 | Are You Sure Delete This Product ? 436 | ( {selectedRow.product_name} ) 437 |

438 | 439 | 442 | 445 | 446 |
447 | 448 | {/* Modal Edit */} 449 | 450 | Edit Category 451 | 452 | 453 | 454 | 455 | 456 | 468 | 469 | 470 | 471 | 485 | 486 | 487 | 488 | 500 | 501 | 502 | 503 | 522 | 523 | 524 | 525 | 544 | 545 | 546 | 547 | 562 | 563 | 564 |
Name 457 | 467 |
Description 472 | 484 |
Image 489 | 499 |
Price 504 | 521 |
Quantity 526 | 543 |
Category 548 | 549 | 560 | 561 |
565 |
566 | 567 | 570 | 573 | 574 | 575 |
576 |
577 |
578 | ) 579 | } 580 | 581 | const mapStateToProps = state => { 582 | return { 583 | dataProducts: state.product.listProduct, 584 | dataCategories: state.categories.listCategory 585 | }; 586 | }; 587 | 588 | export default withRouter (connect (mapStateToProps) (DataProduct)); -------------------------------------------------------------------------------- /src/Components/Layout/ListMenu.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from "react-router-dom"; 3 | import { Divider } from '@material-ui/core'; 4 | import ListItem from '@material-ui/core/ListItem'; 5 | import ListItemIcon from '@material-ui/core/ListItemIcon'; 6 | import ListItemText from '@material-ui/core/ListItemText'; 7 | import AssignmentOutlinedIcon from '@material-ui/icons/AssignmentOutlined'; 8 | import InsertChartIcon from '@material-ui/icons/InsertChart'; 9 | import FastfoodIcon from '@material-ui/icons/Fastfood'; 10 | 11 | //Import Content Button 12 | import Logout from '../Page/Logout'; 13 | 14 | export const mainListMenu = ( 15 | 16 |
17 | {/* Button Snack */} 18 | 19 | 20 | 21 | 22 | List MSG 23 | 24 | 25 | {/* Button Management Product*/} 26 | 27 | 28 | 29 | 30 | Data Product 31 | 32 | 33 | {/* Button Management Category*/} 34 | 35 | 36 | 37 | 38 | Data Category 39 | 40 | 41 | {/* Button Statistic */} 42 | 43 | 44 | 45 | 46 | Statistic 47 | 48 | 49 | 50 | 51 | {/* Button Logout */} 52 | 53 | 54 |
55 | ); -------------------------------------------------------------------------------- /src/Components/Layout/MainPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import clsx from 'clsx'; 3 | // import { useDispatch, useSelector } from 'react-redux'; 4 | import { withRouter} from 'react-router-dom'; 5 | import { useStyles } from '../Styles/StyleMainPage'; 6 | import {Typography, Grid, Paper, Button} from '@material-ui/core/'; 7 | import { connect } from 'react-redux'; 8 | 9 | //Card 10 | import ProductCard from './CardProduct'; 11 | import OrderCard from './CardOrder'; 12 | 13 | function MainPage (props) { 14 | 15 | const classes = useStyles(); 16 | const fixedHeightPaper = clsx(classes.paper, classes.fixedHeight); 17 | // const addProduct = useSelector(state => state.order.addedItem); 18 | 19 | return ( 20 | 21 | 22 | 23 | {/* List Product */} 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | CART 34 | 35 | 36 | 37 | {/* List Order */} 38 | 44 | {props.addedItem.length == 0 ? "EMPTY CART" : props.addedItem.map(item => ( 45 | 46 | ))} 47 | 48 | 49 | 50 | 51 | 52 | 55 | 58 | 59 | 60 | 61 | 62 | 63 | ) 64 | } 65 | 66 | const mapStateToProps = state => { 67 | return { 68 | addedItem: state.order.addedItem 69 | }; 70 | }; 71 | 72 | export default withRouter (connect (mapStateToProps) (MainPage)); 73 | // export default withRouter(MainPage); -------------------------------------------------------------------------------- /src/Components/Layout/Message.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import clsx from 'clsx'; 3 | import { Redirect, withRouter } from 'react-router-dom'; 4 | import { Typography, Grid, Paper} from '@material-ui/core/'; 5 | import { useStyles } from '../Styles/StyleMessage'; 6 | 7 | function Message (props) { 8 | const classes = useStyles(); 9 | const fixedHeightPaper = clsx(classes.paper, classes.fixedHeight); 10 | 11 | return ( 12 | 13 | 14 | 15 | 16 | Welcome To MSG MART !! 17 | 18 | 19 | @Aldo Ignata Chandra 20 | 21 | 22 | 23 | 24 | ) 25 | } 26 | 27 | export default withRouter(Message); -------------------------------------------------------------------------------- /src/Components/Layout/Statistic.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import clsx from 'clsx'; 3 | import { withRouter } from 'react-router-dom'; 4 | import { Typography } from '@material-ui/core/'; 5 | import { useStyles } from '../Styles/StyleDataCategory'; 6 | 7 | function Statistic (props) { 8 | const classes = useStyles(); 9 | 10 | return ( 11 |
12 | 13 | DATA STATISTIC 14 | 15 | 17 | 18 |
19 | ) 20 | } 21 | 22 | export default withRouter(Statistic); -------------------------------------------------------------------------------- /src/Components/Layout/TestPagination.js: -------------------------------------------------------------------------------- 1 | import React, {useState, useEffect} from 'react'; 2 | import { makeStyles } from '@material-ui/core/styles'; 3 | import Table from '@material-ui/core/Table'; 4 | import TableBody from '@material-ui/core/TableBody'; 5 | import TableCell from '@material-ui/core/TableCell'; 6 | import TableHead from '@material-ui/core/TableHead'; 7 | import TablePagination from '@material-ui/core/TablePagination'; 8 | import TableRow from '@material-ui/core/TableRow'; 9 | import Paper from '@material-ui/core/Paper'; 10 | import axios from 'axios'; 11 | import { Redirect } from 'react-router-dom'; 12 | 13 | const useStyles = makeStyles(theme => ({ 14 | root: { 15 | width: '100%', 16 | marginTop: theme.spacing(3), 17 | }, 18 | paper: { 19 | width: '100%', 20 | marginBottom: theme.spacing(2), 21 | }, 22 | table: { 23 | minWidth: 750, 24 | }, 25 | tableWrapper: { 26 | overflowX: 'auto', 27 | }, 28 | visuallyHidden: { 29 | border: 0, 30 | clip: 'rect(0 0 0 0)', 31 | height: 1, 32 | margin: -1, 33 | overflow: 'hidden', 34 | padding: 0, 35 | position: 'absolute', 36 | top: 20, 37 | width: 1, 38 | }, 39 | })); 40 | 41 | const headCells = [ 42 | { id: 'Name', numeric: false, disablePadding: true, label: 'Name' }, 43 | { id: 'Action', numeric: true, disablePadding: false, label: 'Action' }, 44 | ]; 45 | 46 | function EnhancedTableHead(props) { 47 | 48 | return ( 49 | 50 | 51 | 52 | {headCells.map(headCell => ( 53 | 58 | {headCell.label} 59 | 60 | ))} 61 | 62 | 63 | ); 64 | } 65 | 66 | export default function EnhancedTable() { 67 | 68 | const classes = useStyles(); 69 | const [dataCategory, setDataCategory] = useState ([]); 70 | const [token, setToken] = useState (localStorage.getItem("jwt")); 71 | const [page, setPage] = useState(0); 72 | const [infoPage, setInfoPage] = useState({maxPage: 0, totalAllCategories: 0}); 73 | const [rowsPerPage, setRowsPerPage] = useState(5); 74 | const apiCategory = `https://pointofsalesapp.herokuapp.com/api/category` 75 | 76 | const fetchDataCategory = async () => { 77 | console.log(rowsPerPage, page, "uye") 78 | if (token === null) { 79 | return 80 | } else { 81 | const res = await axios (apiCategory, {headers: {"x-access-token":token}, 82 | params: { 83 | item: rowsPerPage, 84 | page: page+1 85 | }}); 86 | setDataCategory (res.data.result.response); 87 | setInfoPage (res.data.result.infoPage); 88 | console.log (res); 89 | } 90 | } 91 | 92 | const handleChangePage = (event, newPage) => { 93 | setPage(newPage); 94 | }; 95 | 96 | const handleChangeRowsPerPage = event => { 97 | setRowsPerPage(parseInt(event.target.value, 10)); 98 | setPage(0); 99 | }; 100 | 101 | const emptyRows = rowsPerPage - Math.min(rowsPerPage, infoPage.totalAllCategories - page * rowsPerPage); 102 | 103 | useEffect(() => { 104 | fetchDataCategory (); 105 | },[page, rowsPerPage]) 106 | 107 | return ( 108 |
109 | 110 |
111 | 117 | 118 | 119 | {dataCategory 120 | .map((row, index) => { 121 | const labelId = `enhanced-table-checkbox-${index}`; 122 | 123 | return ( 124 | 129 | 130 | 131 | 132 | {row.name} 133 | 134 | Action 135 | 136 | ); 137 | })} 138 | {emptyRows > 0 && ( 139 | 140 | 141 | 142 | )} 143 | 144 |
145 |
146 | 147 | 162 | 163 |
164 |
165 | ); 166 | } -------------------------------------------------------------------------------- /src/Components/Page/Dashboard.js: -------------------------------------------------------------------------------- 1 | import React, {useState} from 'react'; 2 | import clsx from 'clsx'; 3 | import { withRouter, Redirect, Route } from "react-router-dom"; 4 | import { useStyles } from '../Styles/StyleDashboard'; 5 | import MenuIcon from '@material-ui/icons/Menu'; 6 | import ChevronLeftIcon from '@material-ui/icons/ChevronLeft'; 7 | import { CssBaseline, Drawer, AppBar, Toolbar, List, Typography, 8 | Divider, IconButton } from '@material-ui/core/'; 9 | 10 | //Import Button Menu 11 | import { mainListMenu } from '../Layout/ListMenu'; 12 | 13 | //Import Content 14 | import Message from '../Layout/Message'; 15 | import MainPage from '../Layout/MainPage'; 16 | import DataCategory from '../Layout/DataCategory'; 17 | import DataProduct from '../Layout/DataProduct'; 18 | import Statistic from '../Layout/Statistic'; 19 | 20 | import EnhancedTable from '../Layout/TestPagination'; 21 | 22 | function Dashboard (props) { 23 | 24 | const classes = useStyles(); 25 | const [token, setToken] = useState (localStorage.getItem("jwt")); 26 | const [openDrawer, setOpenDrawer] = useState (false); 27 | 28 | //Handle Animation Open Menu List 29 | const handleDrawerOpen = () => { 30 | setOpenDrawer(true); 31 | }; 32 | 33 | //Handle Animation Close Menu List 34 | const handleDrawerClose = () => { 35 | setOpenDrawer(false); 36 | }; 37 | 38 | return ( 39 |
40 | 41 | 42 | 43 | 44 | 51 | 52 | 53 | 54 | MSG MART 55 | 56 | 57 | 58 | 59 | 66 |
67 | 68 | Menu 69 | 70 | 71 | 72 | 73 |
74 | 75 | { mainListMenu } 76 |
77 | 78 |
79 |
80 | {/* CONTENT */} 81 | 82 | {!token ? : ()} 83 | 84 | 85 | {!token ? : ()} 86 | 87 | 88 | {!token ? : ()} 89 | 90 | 91 | {!token ? : ()} 92 | 93 | 94 | {!token ? : ()} 95 | 96 | 97 | {!token ? : ()} 98 | 99 |
100 |
101 | ) 102 | } 103 | 104 | export default withRouter(Dashboard); -------------------------------------------------------------------------------- /src/Components/Page/Login.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import clsx from 'clsx'; 3 | import { Link, withRouter } from 'react-router-dom'; 4 | import { Avatar, Button, CssBaseline, TextField,Grid, Typography, Container } from '@material-ui/core'; 5 | import { useStyles } from '../Styles/StyleSignUp'; 6 | import Snackbar from '@material-ui/core/Snackbar'; 7 | import CheckCircleIcon from '@material-ui/icons/CheckCircle'; 8 | import ErrorIcon from '@material-ui/icons/Error'; 9 | import SnackbarContent from '@material-ui/core/SnackbarContent'; 10 | 11 | import { connect } from 'react-redux'; 12 | import { postLogin } from '../Redux/Actions/auth'; 13 | 14 | const variantIcon = { 15 | success: CheckCircleIcon, 16 | error: ErrorIcon, 17 | }; 18 | 19 | function MySnackbarContentWrapper(props) { 20 | const classes = useStyles(); 21 | const { className, message, variant } = props; 22 | const Icon = variantIcon[variant]; 23 | 24 | return ( 25 | 30 | 31 | {message} 32 | 33 | } 34 | /> 35 | ); 36 | } 37 | 38 | function Login (props) { 39 | const classes = useStyles(); 40 | const [input, setInput] = useState({username:'', password:''}) 41 | const [showStatus, setShowStatus] = useState(false); 42 | const [validate, setValidate] = useState (""); 43 | const [success, setSuccess] = useState ("error") 44 | 45 | const login = async (e) => { 46 | e.preventDefault(); 47 | 48 | await props.dispatch(postLogin (input)) 49 | .then((result) => { 50 | if (result.value.data.status !== 400){ 51 | localStorage.setItem("jwt", result.value.data.result.token); 52 | setSuccess("success"); 53 | setValidate("Login Success"); 54 | setShowStatus(true); 55 | setTimeout(() => { 56 | props.history.push('/dashboard') 57 | }, 500); 58 | } else { 59 | setValidate(result.value.data.error); 60 | setShowStatus(true); 61 | } 62 | }) 63 | .catch((error) => setShowStatus(false)) 64 | } 65 | 66 | const onChangeLogin = (e) => { 67 | e.persist() 68 | setInput({...input, [e.target.name] : e.target.value}) 69 | } 70 | 71 | const handleCloseSnackbar = () => { 72 | setShowStatus(false); 73 | }; 74 | 75 | return ( 76 |
77 | 86 | 91 | 92 | 93 | 94 | 95 |
96 | 97 | 98 | Login 99 | 100 |
101 | 111 | 120 | 129 | 130 | 131 |
132 | Don't have account ? Sign up 133 |
134 |
135 | 136 |
137 |
138 |
139 | ); 140 | } 141 | 142 | const mapStateToProps = state => { 143 | return { 144 | response: state.auth.loginResponse 145 | }; 146 | }; 147 | 148 | export default connect (mapStateToProps) (Login); -------------------------------------------------------------------------------- /src/Components/Page/Logout.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import clsx from 'clsx'; 3 | import { withRouter } from 'react-router-dom'; 4 | import { ListItem, ListItemIcon, ListItemText } from '@material-ui/core'; 5 | import Dialog from '@material-ui/core/Dialog'; 6 | import DialogActions from '@material-ui/core/DialogActions'; 7 | import DialogTitle from '@material-ui/core/DialogTitle'; 8 | import ExitToAppIcon from '@material-ui/icons/ExitToApp'; 9 | import Button from '@material-ui/core/Button'; 10 | import Snackbar from '@material-ui/core/Snackbar'; 11 | import CheckCircleIcon from '@material-ui/icons/CheckCircle'; 12 | import ErrorIcon from '@material-ui/icons/Error'; 13 | import SnackbarContent from '@material-ui/core/SnackbarContent'; 14 | import { useStyles } from '../Styles/StyleLogout'; 15 | 16 | const variantIcon = { 17 | success: CheckCircleIcon, 18 | error: ErrorIcon, 19 | }; 20 | 21 | function MySnackbarContentWrapper(props) { 22 | const classes = useStyles(); 23 | const { className, message, variant } = props; 24 | const Icon = variantIcon[variant]; 25 | 26 | return ( 27 | 32 | 33 | {message} 34 | 35 | } 36 | /> 37 | ); 38 | } 39 | 40 | function Logout (props) { 41 | 42 | // const classes = useStyles(); 43 | const [token, setToken] = useState (localStorage.getItem("jwt")); 44 | const [alert, setAlert] = useState (false); 45 | const [showStatus, setShowStatus] = useState(false); 46 | 47 | const logout = () => { 48 | setAlert (false) 49 | setShowStatus (true); 50 | setToken (localStorage.clear()); 51 | setTimeout(() => { 52 | props.history.push ('/'); 53 | }, 750); 54 | } 55 | 56 | const handleAlertOpen = () => { setAlert (true) } 57 | const handleAlertClose = () => { setAlert (false) } 58 | const handleCloseSnackbar = () => { setShowStatus (false) } 59 | 60 | const classes = useStyles(); 61 | 62 | return ( 63 |
64 | 73 | 78 | 79 | 80 | {/* Button Logout */} 81 | 82 | 83 | 84 | 85 | Logout 86 | 87 | 88 | {/* Modal Logout */} 89 | 90 | 91 | Are You Sure Want To Logout From MSG MART ? 92 | 93 |

94 | 95 | 98 | 101 | 102 |
103 |
104 | ) 105 | } 106 | 107 | export default withRouter(Logout); -------------------------------------------------------------------------------- /src/Components/Page/SignUp.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import clsx from 'clsx'; 3 | import { Link, withRouter } from "react-router-dom"; 4 | import { Avatar, Button, CssBaseline ,TextField, Grid, Typography, Container } from '@material-ui/core'; 5 | import { useStyles } from '../Styles/StyleSignUp'; 6 | import Snackbar from '@material-ui/core/Snackbar'; 7 | import CheckCircleIcon from '@material-ui/icons/CheckCircle'; 8 | import ErrorIcon from '@material-ui/icons/Error'; 9 | import SnackbarContent from '@material-ui/core/SnackbarContent'; 10 | 11 | import { connect } from 'react-redux'; 12 | import { postRegister } from '../Redux/Actions/auth'; 13 | 14 | const variantIcon = { 15 | success: CheckCircleIcon, 16 | error: ErrorIcon, 17 | }; 18 | 19 | function MySnackbarContentWrapper(props) { 20 | const classes = useStyles(); 21 | const { className, message, variant } = props; 22 | const Icon = variantIcon[variant]; 23 | 24 | return ( 25 | 30 | 31 | {message} 32 | 33 | } 34 | /> 35 | ); 36 | } 37 | 38 | function SignUp (props) { 39 | 40 | const classes = useStyles(); 41 | const [input, setInput] = useState({ username: "", password: "", role: "" }); 42 | const [showStatus, setShowStatus] = useState(false); 43 | const [validate, setValidate] = useState (""); 44 | const [success, setSuccess] = useState ("error") 45 | 46 | const register = async(e) => { 47 | e.preventDefault(); 48 | 49 | await props.dispatch(postRegister (input)) 50 | .then((result) => { 51 | console.log(result); 52 | if (result.value.data.status !== 400){ 53 | setValidate(result.value.data.result); 54 | setSuccess("success"); 55 | setShowStatus(true); 56 | setTimeout(() => { 57 | props.history.push('/') 58 | }, 1000); 59 | } else { 60 | setValidate(result.value.data.error) 61 | setShowStatus(true); 62 | } 63 | }).catch((error) => setShowStatus(false)); 64 | } 65 | 66 | const onChangeSignup = (e) => { 67 | e.persist() 68 | setInput({...input, [e.target.name] : e.target.value}) 69 | } 70 | 71 | const handleCloseSnackbar = () => { 72 | setShowStatus(false); 73 | }; 74 | 75 | return ( 76 |
77 | 86 | 91 | 92 | 93 | 94 | 95 |
96 | 97 | 98 | Sign Up 99 | 100 |
101 | 111 | 120 | 129 | 138 | 139 | 140 | Already have an account ? back to Login 141 | 142 | 143 | 144 |
145 |
146 |
147 | ); 148 | } 149 | 150 | const mapStateToProps = state => { 151 | return { 152 | response: state.auth.registerResponse 153 | }; 154 | }; 155 | 156 | export default connect (mapStateToProps) (SignUp); -------------------------------------------------------------------------------- /src/Components/Redux/Actions/auth.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export const postRegister = (input) => { 4 | return { 5 | type: 'POST_REGISTER', 6 | payload: axios.post ('https://pointofsalesapp.herokuapp.com/api/user/register/',input), 7 | }; 8 | }; 9 | 10 | export const postLogin = (input) => { 11 | return { 12 | type: 'POST_LOGIN', 13 | payload: axios.post ('https://pointofsalesapp.herokuapp.com/api/user/login/',input), 14 | }; 15 | }; -------------------------------------------------------------------------------- /src/Components/Redux/Actions/categories.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export const getCategories = (item, page) => { 4 | const token = localStorage.getItem("jwt"); 5 | return { 6 | type: 'GET_CATEGORIES', 7 | payload: axios.get ('https://pointofsalesapp.herokuapp.com/api/category/',{ 8 | params: { 9 | item, 10 | page 11 | }, 12 | headers: {"x-access-token":token}, 13 | }) 14 | }; 15 | }; 16 | 17 | export const postCategories = (input) => { 18 | const token = localStorage.getItem("jwt"); 19 | return { 20 | type: 'POST_CATEGORIES', 21 | payload: axios.post ('https://pointofsalesapp.herokuapp.com/api/category/', input, { headers: {"x-access-token":token} } ) 22 | }; 23 | }; 24 | 25 | export const patchCategories = (input) => { 26 | const token = localStorage.getItem("jwt"); 27 | const id = input.id; 28 | return { 29 | type: 'PATCH_CATEGORIES', 30 | payload: axios.put ('https://pointofsalesapp.herokuapp.com/api/category/'+id, input, { headers: {"x-access-token":token} }) 31 | }; 32 | }; 33 | 34 | export const deleteCategories = (input) => { 35 | const token = localStorage.getItem("jwt"); 36 | const id = input.id; 37 | return { 38 | type: 'DELETE_CATEGORIES', 39 | payload: axios.delete ('https://pointofsalesapp.herokuapp.com/api/category/'+id, { headers: {"x-access-token":token} }) 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /src/Components/Redux/Actions/order.js: -------------------------------------------------------------------------------- 1 | export const addToCart = (item) => { 2 | return { 3 | type: 'ADD_TO_CART', 4 | item 5 | } 6 | } 7 | 8 | //remove item action 9 | export const removeItem = (item) =>{ 10 | return{ 11 | type: 'REMOVE_ITEM', 12 | item 13 | } 14 | } 15 | 16 | //subtract qt action 17 | export const subtractQuantity = (item) => { 18 | return{ 19 | type: 'SUB_QUANTITY', 20 | item 21 | } 22 | } 23 | 24 | //add qt action 25 | export const addQuantity = (item) => { 26 | return{ 27 | type: 'ADD_QUANTITY', 28 | item 29 | } 30 | } -------------------------------------------------------------------------------- /src/Components/Redux/Actions/product.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export const getProducts = (item, page) => { 4 | const token = localStorage.getItem("jwt"); 5 | return { 6 | type: 'GET_PRODUCT', 7 | payload: axios.get ('https://pointofsalesapp.herokuapp.com/api/product/',{ 8 | params: { 9 | item, 10 | page 11 | }, 12 | headers: {"x-access-token":token}, 13 | }) 14 | }; 15 | }; 16 | 17 | export const postProducts = (input) => { 18 | const token = localStorage.getItem("jwt"); 19 | return { 20 | type: 'POST_PRODUCT', 21 | payload: axios.post ('https://pointofsalesapp.herokuapp.com/api/product/', input, { headers: {"x-access-token":token} } ) 22 | }; 23 | }; 24 | 25 | export const patchProducts = (input) => { 26 | const token = localStorage.getItem("jwt"); 27 | const id = input.id; 28 | return { 29 | type: 'PATCH_PRODUCT', 30 | payload: axios.put ('https://pointofsalesapp.herokuapp.com/api/product/'+id, input, { headers: {"x-access-token":token} }) 31 | }; 32 | }; 33 | 34 | export const deleteProducts = (input) => { 35 | const token = localStorage.getItem("jwt"); 36 | const id = input.id; 37 | return { 38 | type: 'DELETE_PRODUCT', 39 | payload: axios.delete ('https://pointofsalesapp.herokuapp.com/api/product/'+id, { headers: {"x-access-token":token} }) 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /src/Components/Redux/Reducers/auth.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | registerResponse: [], 3 | loginResponse: [], 4 | isLoading: false, 5 | isRejected: false, 6 | isFulfilled: false, 7 | }; 8 | 9 | const auth = (state = initialState, action) => { 10 | switch (action.type) { 11 | case 'POST_REGISTER_PENDING': 12 | return { 13 | ...state, 14 | isLoading: true, 15 | isRejected: false, 16 | isFulfilled: false, 17 | }; 18 | case 'POST_REGISTER_REJECTED': 19 | return { 20 | ...state, 21 | isLoading: false, 22 | isRejected: true, 23 | }; 24 | case 'POST_REGISTER_FULFILLED': 25 | return { 26 | ...state, 27 | isLoading: false, 28 | isFulfilled: true, 29 | registerResponse: action.payload, 30 | }; 31 | //------------------------------------------------------------- 32 | case 'POST_LOGIN_PENDING': 33 | return { 34 | ...state, 35 | isLoading: true, 36 | isRejected: false, 37 | isFulfilled: false, 38 | }; 39 | case 'POST_LOGIN_REJECTED': 40 | return { 41 | ...state, 42 | isLoading: false, 43 | isRejected: true, 44 | }; 45 | case 'POST_LOGIN_FULFILLED': 46 | return { 47 | ...state, 48 | isLoading: false, 49 | isFulfilled: true, 50 | loginResponse: action.payload, 51 | }; 52 | 53 | default: 54 | return state; 55 | } 56 | }; 57 | 58 | export default auth; -------------------------------------------------------------------------------- /src/Components/Redux/Reducers/categories.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | listCategory: [], 3 | isLoading: false, 4 | isRejected: false, 5 | isFulfilled: false, 6 | }; 7 | 8 | const categories = (state = initialState, action) => { 9 | switch (action.type) { 10 | // GET CATEGORIES 11 | case 'GET_CATEGORIES_PENDING': 12 | return { 13 | ...state, 14 | isLoading: true, 15 | isRejected: false, 16 | isFulfilled: false, 17 | }; 18 | case 'GET_CATEGORIES_REJECTED': 19 | return { 20 | ...state, 21 | isLoading: false, 22 | isRejected: true, 23 | }; 24 | case 'GET_CATEGORIES_FULFILLED': 25 | return { 26 | ...state, 27 | isLoading: false, 28 | isFulfilled: true, 29 | listCategory: action.payload.data.result.response, 30 | }; 31 | 32 | // POST CATEGORIES 33 | case 'POST_CATEGORIES_PENDING': 34 | return { 35 | ...state, 36 | isLoading: true, 37 | isRejected: false, 38 | isFulfilled: false, 39 | }; 40 | case 'POST_CATEGORIES_REJECTED': 41 | return { 42 | ...state, 43 | isLoading: false, 44 | isRejected: true, 45 | }; 46 | case 'POST_CATEGORIES_FULFILLED': 47 | if (action.payload.data.status == 200) 48 | state.listCategory.push (action.payload.data.result[0]) 49 | return { 50 | ...state, 51 | isLoading: false, 52 | isFulfilled: true, 53 | listCategory: state.listCategory, 54 | }; 55 | 56 | // EDIT CATEGORIES 57 | case 'PATCH_CATEGORIES_PENDING': 58 | return { 59 | ...state, 60 | isLoading: true, 61 | isRejected: false, 62 | isFulfilled: false, 63 | }; 64 | case 'PATCH_CATEGORIES_REJECTED': 65 | return { 66 | ...state, 67 | isLoading: false, 68 | isRejected: true, 69 | }; 70 | case 'PATCH_CATEGORIES_FULFILLED': 71 | const listCategoryAfterPatch = state.listCategory.map (categories => { 72 | if (action.payload.data.status == 200) { 73 | if (categories.id == action.payload.data.response.id) { 74 | return action.payload.data.response; 75 | } 76 | } 77 | return categories; 78 | }); 79 | return { 80 | ...state, 81 | isLoading: false, 82 | isFulfilled: true, 83 | listCategory: listCategoryAfterPatch 84 | }; 85 | 86 | // DELETE CATEGORIES 87 | case 'DELETE_CATEGORIES_PENDING': 88 | return { 89 | ...state, 90 | isLoading: true, 91 | isRejected: false, 92 | isFulfilled: false, 93 | }; 94 | case 'DELETE_CATEGORIES_REJECTED': 95 | return { 96 | ...state, 97 | isLoading: false, 98 | isRejected: true, 99 | }; 100 | case 'DELETE_CATEGORIES_FULFILLED': 101 | const dataAfterDelete = state.listCategory.filter((value) => { 102 | return value.id != action.payload.data.id }); 103 | return { 104 | ...state, 105 | isLoading: false, 106 | isFulfilled: true, 107 | listCategory: dataAfterDelete, 108 | }; 109 | 110 | default: 111 | return state; 112 | } 113 | }; 114 | 115 | export default categories; -------------------------------------------------------------------------------- /src/Components/Redux/Reducers/index.js: -------------------------------------------------------------------------------- 1 | 2 | import { combineReducers } from 'redux'; 3 | 4 | import auth from './auth'; 5 | import product from './product'; 6 | import categories from './categories'; 7 | import order from './order'; 8 | 9 | const appReducer = combineReducers ({ 10 | auth, 11 | product, 12 | categories, 13 | order 14 | }); 15 | 16 | export default appReducer; -------------------------------------------------------------------------------- /src/Components/Redux/Reducers/order.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | addedItem: [], 3 | total: 0, 4 | isLoading: false, 5 | isRejected: false, 6 | isFulfilled: false, 7 | }; 8 | 9 | const order = (state = initialState, action) => { 10 | switch (action.type) { 11 | //Add Selected Product To Cart 12 | case 'ADD_TO_CART': 13 | let existed_item = state.addedItem.find( product => action.item.id === product.id ) 14 | 15 | state.addedItem.push ({ 16 | id: action.item.id, 17 | product_name: action.item.product_name, 18 | image: action.item.image, 19 | price: action.item.price, 20 | quantity: action.item.quantity, 21 | totalQty: 1 22 | }); 23 | 24 | if(existed_item) 25 | { 26 | state.addedItem.quantity += 1 27 | return { 28 | ...state, 29 | // total: state.total + state.addedItem.price 30 | } 31 | } else { 32 | // state.addedItem.quantity = 1; 33 | return { 34 | ...state, 35 | addedItem: state.addedItem, 36 | // total : state.total + state.addedItem.price 37 | } 38 | } 39 | case 'ADD_QUANTITY': 40 | let addeQuantity = state.addedItems.find(item=> item.id_product === action.id) 41 | addeQuantity.quantity += 1 42 | let Totaladd = state.total + addeQuantity.price 43 | return{ 44 | ...state, 45 | total: Totaladd 46 | } 47 | case 'SUB_QUANTITY': 48 | let subQuantity = state.addedItems.find(item=> item.id_product === action.id) 49 | subQuantity.quantity -= 1 50 | let Totalsub = state.total - subQuantity.price 51 | return { 52 | ...state, 53 | total: Totalsub 54 | } 55 | case 'REMOVE_ITEM': 56 | let itemToRemove= state.addedItems.find(item=> action.id === item.id_product) 57 | let new_items = state.addedItems.filter(item=> action.id !== item.id_product) 58 | 59 | //calculating the total 60 | let newTotal = state.total - (itemToRemove.price * itemToRemove.quantity ) 61 | return { 62 | ...state, 63 | addedItems: new_items, 64 | total: newTotal 65 | } 66 | 67 | default: 68 | return state; 69 | } 70 | }; 71 | 72 | export default order; -------------------------------------------------------------------------------- /src/Components/Redux/Reducers/product.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | listProduct: [], 3 | isLoading: false, 4 | isRejected: false, 5 | isFulfilled: false, 6 | addedItem: [], 7 | total: 0, 8 | }; 9 | 10 | const product = (state = initialState, action) => { 11 | switch (action.type) { 12 | // GET PRODUCT 13 | case 'GET_PRODUCT_PENDING': 14 | return { 15 | ...state, 16 | isLoading: true, 17 | isRejected: false, 18 | isFulfilled: false, 19 | }; 20 | case 'GET_PRODUCT_REJECTED': 21 | return { 22 | ...state, 23 | isLoading: false, 24 | isRejected: true, 25 | }; 26 | case 'GET_PRODUCT_FULFILLED': 27 | return { 28 | ...state, 29 | isLoading: false, 30 | isFulfilled: true, 31 | listProduct: action.payload.data.result.response, 32 | }; 33 | 34 | //POST PRODUCT 35 | case 'POST_PRODUCT_PENDING': 36 | return { 37 | ...state, 38 | isLoading: true, 39 | isRejected: false, 40 | isFulfilled: false, 41 | }; 42 | case 'POST_PRODUCT_REJECTED': 43 | return { 44 | ...state, 45 | isLoading: false, 46 | isRejected: true, 47 | }; 48 | case 'POST_PRODUCT_FULFILLED': 49 | if (action.payload.data.status == 200) 50 | state.listProduct.push (action.payload.data.result[0]) 51 | return { 52 | ...state, 53 | isLoading: false, 54 | isFulfilled: true, 55 | listProduct: state.listProduct, 56 | }; 57 | 58 | //EDIT PRODUCT 59 | case 'PATCH_PRODUCT_PENDING': 60 | return { 61 | ...state, 62 | isLoading: true, 63 | isRejected: false, 64 | isFulfilled: false, 65 | }; 66 | case 'PATCH_PRODUCT_REJECTED': 67 | return { 68 | ...state, 69 | isLoading: false, 70 | isRejected: true, 71 | }; 72 | case 'PATCH_PRODUCT_FULFILLED': 73 | const listProductAfterPatch = state.listProduct.map (products => { 74 | if (action.payload.data.status == 200) { 75 | if (products.id == action.payload.data.result[0].id) { 76 | return action.payload.data.result[0]; 77 | } 78 | } 79 | return products; 80 | }); 81 | return { 82 | ...state, 83 | isLoading: false, 84 | isFulfilled: true, 85 | listProduct: listProductAfterPatch 86 | }; 87 | 88 | //DELETE PRODUCT 89 | case 'DELETE_PRODUCT_PENDING': 90 | return { 91 | ...state, 92 | isLoading: true, 93 | isRejected: false, 94 | isFulfilled: false, 95 | }; 96 | case 'DELETE_PRODUCT_REJECTED': 97 | return { 98 | ...state, 99 | isLoading: false, 100 | isRejected: true, 101 | }; 102 | case 'DELETE_PRODUCT_FULFILLED': 103 | const dataAfterDelete = state.listProduct.filter((value) => { 104 | return value.id != action.payload.data.id }); 105 | return { 106 | ...state, 107 | isLoading: false, 108 | isFulfilled: true, 109 | listProduct: dataAfterDelete, 110 | }; 111 | 112 | default: 113 | return state; 114 | } 115 | }; 116 | 117 | export default product; -------------------------------------------------------------------------------- /src/Components/Redux/store.js: -------------------------------------------------------------------------------- 1 | import {createStore, applyMiddleware} from 'redux'; 2 | import {createLogger} from 'redux-logger'; 3 | import promiseMiddleware from 'redux-promise-middleware'; 4 | 5 | import Reducers from './Reducers'; 6 | 7 | const logger = createLogger (); 8 | const middleware = applyMiddleware (logger, promiseMiddleware); 9 | const store = createStore (Reducers, middleware); 10 | 11 | export default store; -------------------------------------------------------------------------------- /src/Components/Styles/StyleDashboard.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from '@material-ui/core/styles'; 2 | 3 | const drawerWidth = 240; 4 | export const useStyles = makeStyles(theme => ({ 5 | root: { 6 | display: 'flex', 7 | }, 8 | toolbar: { 9 | paddingRight: 24, // keep right padding when drawer closed 10 | }, 11 | toolbarIcon: { 12 | display: 'flex', 13 | alignItems: 'center', 14 | justifyContent: 'flex-end', 15 | padding: '0 8px', 16 | ...theme.mixins.toolbar, 17 | }, 18 | appBar: { 19 | backgroundColor: "#ffce1e", 20 | zIndex: theme.zIndex.drawer + 1, 21 | transition: theme.transitions.create(['width', 'margin'], { 22 | easing: theme.transitions.easing.sharp, 23 | duration: theme.transitions.duration.leavingScreen, 24 | }), 25 | }, 26 | appBarShift: { 27 | marginLeft: drawerWidth, 28 | width: `calc(100% - ${drawerWidth}px)`, 29 | transition: theme.transitions.create(['width', 'margin'], { 30 | easing: theme.transitions.easing.sharp, 31 | duration: theme.transitions.duration.enteringScreen, 32 | }), 33 | }, 34 | menuButton: { 35 | marginRight: 36, 36 | }, 37 | menuButtonHidden: { 38 | display: 'none', 39 | }, 40 | title: { 41 | color: "#34495e", 42 | flexGrow: 1, 43 | fontFamily: "Airbnb Cereal App", 44 | fontWeight: "bold", 45 | textAlign: "center", 46 | fontSize: "40px" 47 | }, 48 | subMenu: { 49 | flexGrow: 1, 50 | fontFamily: "Airbnb Cereal App", 51 | fontWeight: "bold", 52 | textAlign: "center", 53 | fontSize: "30px" 54 | }, 55 | drawerPaper: { 56 | position: 'relative', 57 | whiteSpace: 'nowrap', 58 | width: drawerWidth, 59 | transition: theme.transitions.create('width', { 60 | easing: theme.transitions.easing.sharp, 61 | duration: theme.transitions.duration.enteringScreen, 62 | }), 63 | }, 64 | drawerPaperClose: { 65 | overflowX: 'hidden', 66 | transition: theme.transitions.create('width', { 67 | easing: theme.transitions.easing.sharp, 68 | duration: theme.transitions.duration.leavingScreen, 69 | }), 70 | width: theme.spacing(7), 71 | [theme.breakpoints.up('sm')]: { 72 | width: theme.spacing(9), 73 | }, 74 | }, 75 | appBarSpacer: theme.mixins.toolbar, 76 | content: { 77 | flexGrow: 1, 78 | height: '100vh', 79 | overflow: 'auto', 80 | }, 81 | container: { 82 | paddingTop: theme.spacing(4), 83 | paddingBottom: theme.spacing(4), 84 | }, 85 | paper: { 86 | padding: theme.spacing(1), 87 | display: 'flex', 88 | overflow: 'auto', 89 | flexDirection: 'column', 90 | border: "1px solid #CECECE" 91 | }, 92 | fixedHeight: { 93 | height: "89vh", 94 | width: "90wh", 95 | }, 96 | bigavatar: { 97 | margin: theme.spacing(1), 98 | width: 70, 99 | height: 70, 100 | }, 101 | button: { 102 | height: 50, 103 | width: 170, 104 | margin: theme.spacing(2) 105 | }, 106 | })); -------------------------------------------------------------------------------- /src/Components/Styles/StyleDataCategory.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from '@material-ui/core/styles'; 2 | import { green } from '@material-ui/core/colors'; 3 | 4 | export const useStyles = makeStyles(theme => ({ 5 | root: { 6 | width: '100%', 7 | }, 8 | paper: { 9 | marginTop: theme.spacing(3), 10 | margin : theme.spacing(3), 11 | width: '95%', 12 | overflowX: 'auto', 13 | marginBottom: theme.spacing(2), 14 | }, 15 | table: { 16 | minWidth: 650, 17 | }, 18 | tableHeader: { 19 | fontWeight:"bold", 20 | fontSize:"17px" 21 | }, 22 | bigAvatar: { 23 | margin: 10, 24 | width: 60, 25 | height: 60, 26 | }, 27 | title: { 28 | margin : theme.spacing(3), 29 | }, 30 | modal: { 31 | display: 'flex', 32 | alignItems: 'center', 33 | justifyContent: 'center', 34 | }, 35 | textField: { 36 | marginLeft: theme.spacing(1), 37 | marginRight: theme.spacing(1), 38 | width: 400, 39 | height: 50 40 | }, 41 | boldText: { 42 | fontWeight: "bold", 43 | fontSize: "17px" 44 | }, 45 | button: { 46 | borderStyle: "solid", 47 | borderWidth: "2px" 48 | }, 49 | buttonAdd: { 50 | marginLeft: theme.spacing(3), 51 | borderStyle: "solid", 52 | borderWidth: "2px", 53 | color: "#ffce1e", 54 | fontWeight:"bold", 55 | background: "white" 56 | }, 57 | dialogTitle: { 58 | display: 'flex', 59 | alignItems: 'center', 60 | justifyContent: 'center', 61 | }, 62 | success: { 63 | backgroundColor: green[600], 64 | }, 65 | error: { 66 | backgroundColor: theme.palette.error.dark, 67 | }, 68 | icon: { 69 | fontSize: 20, 70 | }, 71 | iconVariant: { 72 | opacity: 0.9, 73 | marginRight: theme.spacing(1), 74 | }, 75 | message: { 76 | display: 'flex', 77 | alignItems: 'center', 78 | }, 79 | maintenance: { 80 | marginLeft: "340px", 81 | width: "500px" 82 | }, 83 | })); -------------------------------------------------------------------------------- /src/Components/Styles/StyleLogout.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from '@material-ui/core/styles'; 2 | import { green } from '@material-ui/core/colors'; 3 | 4 | export const useStyles = makeStyles(theme => ({ 5 | dialogTitle: { 6 | fontFamily: "Arial", 7 | textAlign: "center", 8 | fontWeight: "bold", 9 | color: "red" 10 | }, 11 | buttonText: { 12 | fontWeight: "bold" 13 | }, 14 | button: { 15 | color: "red" 16 | }, 17 | success: { 18 | backgroundColor: green[600], 19 | }, 20 | error: { 21 | backgroundColor: theme.palette.error.dark, 22 | }, 23 | icon: { 24 | fontSize: 20, 25 | }, 26 | iconVariant: { 27 | opacity: 0.9, 28 | marginRight: theme.spacing(1), 29 | }, 30 | message: { 31 | display: 'flex', 32 | alignItems: 'center', 33 | }, 34 | })); -------------------------------------------------------------------------------- /src/Components/Styles/StyleMainPage.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from '@material-ui/core/styles'; 2 | 3 | export const useStyles = makeStyles(theme => ({ 4 | container: { 5 | paddingTop: theme.spacing(4), 6 | paddingBottom: theme.spacing(4), 7 | }, 8 | paper: { 9 | padding: theme.spacing(3), 10 | display: 'flex', 11 | overflow: 'auto', 12 | flexDirection: 'column', 13 | border: "0px solid #CECECE" 14 | }, 15 | fixedHeight: { 16 | height: "89vh", 17 | width: "90wh", 18 | }, 19 | button: { 20 | height: 45, 21 | width: 150, 22 | margin: theme.spacing(1) 23 | }, 24 | cartMaintenance: { 25 | marginTop: "70px", 26 | marginLeft: "60px", 27 | width: "300px" 28 | } 29 | })); -------------------------------------------------------------------------------- /src/Components/Styles/StyleMessage.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from '@material-ui/core/styles'; 2 | 3 | export const useStyles = makeStyles(theme => ({ 4 | container: { 5 | paddingTop: theme.spacing(4), 6 | paddingBottom: theme.spacing(4), 7 | }, 8 | paper: { 9 | padding: theme.spacing(1), 10 | display: 'flex', 11 | overflow: 'auto', 12 | flexDirection: 'column', 13 | textAlign: "center", 14 | }, 15 | fixedHeight: { 16 | height: "50vh", 17 | width: "90wh", 18 | }, 19 | info: { 20 | fontWeight:"bold", 21 | marginTop:"80px" 22 | } 23 | })); -------------------------------------------------------------------------------- /src/Components/Styles/StyleOrderCard.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from '@material-ui/core/styles'; 2 | 3 | export const useStyles = makeStyles(theme => ({ 4 | card: { 5 | display: 'flex', 6 | margin: "3px", 7 | }, 8 | details: { 9 | display: 'flex', 10 | flexDirection: 'column', 11 | }, 12 | content: { 13 | flex: '1 0 auto', 14 | }, 15 | image: { 16 | width: 170, 17 | height: 110, 18 | margin: "5px", 19 | }, 20 | controls: { 21 | display: 'flex', 22 | alignItems: 'center', 23 | justifyContent: "center" 24 | }, 25 | })); -------------------------------------------------------------------------------- /src/Components/Styles/StyleProductCard.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from '@material-ui/core/styles'; 2 | 3 | export const useStyles = makeStyles(theme => ({ 4 | root: { 5 | position: 'fixed', 6 | bottom: theme.spacing(2), 7 | right: theme.spacing(2), 8 | }, 9 | card: { 10 | width: "100%", 11 | maxHeight: 300, 12 | borderRadius: 10, 13 | margin: "5px", 14 | }, 15 | button: { 16 | fontSize: "12px", 17 | height: 30, 18 | width: 50, 19 | background: "#e74c3c" 20 | }, 21 | buttonOrderBy: { 22 | margin: theme.spacing(1), 23 | marginBottom: "10px", 24 | background: "#e67e22", 25 | fontWeight: "bold", 26 | }, 27 | buttonSort: { 28 | margin: theme.spacing(1), 29 | marginBottom: "10px", 30 | background: "#e74c3c", 31 | fontWeight: "bold" 32 | }, 33 | buttonSearch: { 34 | margin: theme.spacing(1), 35 | marginBottom: "10px", 36 | }, 37 | searchField: { 38 | width:"430px", 39 | }, 40 | textError: { 41 | fontWeight: "bold", 42 | margin: "auto", 43 | marginTop: "100px", 44 | color: "#e67e22", 45 | border: "solid" 46 | } 47 | })); -------------------------------------------------------------------------------- /src/Components/Styles/StyleSignUp.js: -------------------------------------------------------------------------------- 1 | import { makeStyles } from '@material-ui/core/styles'; 2 | import { green } from '@material-ui/core/colors'; 3 | 4 | export const useStyles = makeStyles(theme => ({ 5 | '@global': { 6 | body: { 7 | backgroundColor: "#ffce1e", 8 | }, 9 | }, 10 | paper: { 11 | marginTop: theme.spacing(8), 12 | display: 'flex', 13 | flexDirection: 'column', 14 | alignItems: 'center', 15 | }, 16 | bigavatar: { 17 | margin: theme.spacing(1), 18 | width: 70, 19 | height: 70, 20 | }, 21 | form: { 22 | width: '100%', // Fix IE 11 issue. 23 | marginTop: theme.spacing(3), 24 | }, 25 | submit: { 26 | margin: theme.spacing(3, 0, 2), 27 | }, 28 | linkinfo: { 29 | display: 'flex', 30 | flexDirection: 'column', 31 | alignItems: 'center' 32 | }, 33 | success: { 34 | backgroundColor: green[600], 35 | }, 36 | error: { 37 | backgroundColor: theme.palette.error.dark, 38 | }, 39 | icon: { 40 | fontSize: 20, 41 | }, 42 | iconVariant: { 43 | opacity: 0.9, 44 | marginRight: theme.spacing(1), 45 | }, 46 | message: { 47 | display: 'flex', 48 | alignItems: 'center', 49 | }, 50 | })); -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import AppRouter from './AppRouter'; 4 | import * as serviceWorker from './serviceWorker'; 5 | import { Provider } from 'react-redux'; 6 | import store from './Components/Redux/store'; 7 | 8 | const WappedApp = () => { 9 | return ( 10 | 11 | 12 | 13 | ) 14 | } 15 | 16 | ReactDOM.render(, document.getElementById('root')); 17 | 18 | // If you want your app to work offline and load faster, you can change 19 | // unregister() to register() below. Note this comes with some pitfalls. 20 | // Learn more about service workers: https://bit.ly/CRA-PWA 21 | serviceWorker.unregister(); 22 | -------------------------------------------------------------------------------- /src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | --------------------------------------------------------------------------------