diff --git a/package-lock.json b/package-lock.json index 7a4ab34..2b37d5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "axios-app", "version": "0.1.0", "dependencies": { "@emotion/react": "^11.7.0", diff --git a/src/App.css b/src/App.css index 74b5e05..5dd2a17 100644 --- a/src/App.css +++ b/src/App.css @@ -27,7 +27,11 @@ .App-link { color: #61dafb; } - +.single-input-left { + padding: 30px; + width: 100%; + margin: 30px; +} @keyframes App-logo-spin { from { transform: rotate(0deg); diff --git a/src/App.js b/src/App.js index 7a13708..a576229 100644 --- a/src/App.js +++ b/src/App.js @@ -1,24 +1,23 @@ -import logo from './logo.svg'; -import './App.css'; -import Dashboard from './pages/Dashboard' -import Categories from './pages/Categories' -import Products from './pages/Products' -import Login from './pages/Login' -import {Navigate, Route, Routes} from 'react-router-dom' -import {useEffect,useState} from 'react' -import Drawer from './components/Drawer' - +import logo from "./logo.svg"; +import "./App.css"; +import Dashboard from "./pages/Dashboard"; +import Categories from "./pages/Categories"; +import Products from "./pages/Products"; +import Login from "./pages/Login"; +import { Navigate, Route, Routes } from "react-router-dom"; +import { useEffect, useState } from "react"; +import Drawer from "./components/Drawer"; function App(props) { - - - return - }/> - }/> - }/> - }/> - - + return ( + + } /> + } /> + } /> + } /> + } /> + + ); } export default App; diff --git a/src/components/Buttons.jsx b/src/components/Buttons.jsx new file mode 100644 index 0000000..55d4f36 --- /dev/null +++ b/src/components/Buttons.jsx @@ -0,0 +1,17 @@ +import React from "react"; +import Button from "@mui/material/Button"; + +export default function Buttons(props) { + return ( + + ); +} diff --git a/src/components/Drawer.jsx b/src/components/Drawer.jsx index 9e615f1..7012bb6 100644 --- a/src/components/Drawer.jsx +++ b/src/components/Drawer.jsx @@ -1,93 +1,124 @@ -import * as React from 'react'; -import { useEffect } from 'react' -import { styled, useTheme } from '@mui/material/styles'; -import Box from '@mui/material/Box'; -import Drawer from '@mui/material/Drawer'; -import CssBaseline from '@mui/material/CssBaseline'; -import MuiAppBar from '@mui/material/AppBar'; -import Toolbar from '@mui/material/Toolbar'; -import List from '@mui/material/List'; -import Typography from '@mui/material/Typography'; -import Divider from '@mui/material/Divider'; -import IconButton from '@mui/material/IconButton'; -import MenuIcon from '@mui/icons-material/Menu'; -import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'; -import ChevronRightIcon from '@mui/icons-material/ChevronRight'; -import ListItem from '@mui/material/ListItem'; -import ListItemIcon from '@mui/material/ListItemIcon'; -import ListItemText from '@mui/material/ListItemText'; -import InboxIcon from '@mui/icons-material/MoveToInbox'; -import MailIcon from '@mui/icons-material/Mail'; -import { Routes, Link, Route, useLocation, useNavigate } from 'react-router-dom' -import Dashboard from '../pages/Dashboard' -import Categories from '../pages/Categories' -import Products from '../pages/Products' -import LogoutIcon from '@mui/icons-material/Logout'; -import GridViewIcon from '@mui/icons-material/GridView'; -import CategoryIcon from '@mui/icons-material/Category'; -import ProductionQuantityLimitsIcon from '@mui/icons-material/ProductionQuantityLimits'; -import Login from '../pages/Login' -import Avatar from './Avatar' -import MenuItem from '@mui/material/MenuItem'; -import Menu from '@mui/material/Menu'; -import Tooltip from '@mui/material/Tooltip'; -import {navigate} from 'react-router-dom' -import {TOKEN_KEY} from '../utils/Constants' +import React, { useEffect, useState } from "react"; +import { Navigate } from "react-router-dom"; +import { styled, useTheme } from "@mui/material/styles"; +import Box from "@mui/material/Box"; +import Drawer from "@mui/material/Drawer"; +import CssBaseline from "@mui/material/CssBaseline"; +import MuiAppBar from "@mui/material/AppBar"; +import Toolbar from "@mui/material/Toolbar"; +import List from "@mui/material/List"; +import Typography from "@mui/material/Typography"; +import Divider from "@mui/material/Divider"; +import IconButton from "@mui/material/IconButton"; +import MenuIcon from "@mui/icons-material/Menu"; +import ChevronLeftIcon from "@mui/icons-material/ChevronLeft"; +import ChevronRightIcon from "@mui/icons-material/ChevronRight"; +import ListItem from "@mui/material/ListItem"; +import ListItemIcon from "@mui/material/ListItemIcon"; +import ListItemText from "@mui/material/ListItemText"; -const drawerWidth = 240; +import { Link, useLocation, useNavigate } from "react-router-dom"; +import Dashboard from "../pages/Dashboard"; +import Categories from "../pages/Categories"; +import Products from "../pages/Products"; +import CartPage from "../pages/CartPage"; +import LogoutIcon from "@mui/icons-material/Logout"; +import GridViewIcon from "@mui/icons-material/GridView"; +import CategoryIcon from "@mui/icons-material/Category"; +import ProductionQuantityLimitsIcon from "@mui/icons-material/ProductionQuantityLimits"; +import Login from "../pages/Login"; +import Avatar from "./Avatar"; +import MenuItem from "@mui/material/MenuItem"; +import Menu from "@mui/material/Menu"; +import Tooltip from "@mui/material/Tooltip"; +import ShoppingCartIcon from "@mui/icons-material/ShoppingCart"; +import { TOKEN_KEY } from "../utils/Constants"; +import Badge from "@mui/material/Badge"; +import Stack from "@mui/material/Stack"; +import Snackbar from "@mui/material/Snackbar"; -const Main = styled('main', { shouldForwardProp: (prop) => prop !== 'open' })( - ({ theme, open }) => ({ - flexGrow: 1, - padding: theme.spacing(3), - transition: theme.transitions.create('margin', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.leavingScreen, - }), - marginLeft: `-${drawerWidth}px`, - ...(open && { - transition: theme.transitions.create('margin', { - easing: theme.transitions.easing.easeOut, - duration: theme.transitions.duration.enteringScreen, - }), - marginLeft: 0, +import MuiAlert from "@mui/material/Alert"; +const drawerWidth = 240; + +const Main = styled("main", { shouldForwardProp: (prop) => prop !== "open" })(({ theme, open }) => ({ + flexGrow: 1, + padding: theme.spacing(3), + transition: theme.transitions.create("margin", { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.leavingScreen, + }), + marginLeft: `-${drawerWidth}px`, + ...(open && { + transition: theme.transitions.create("margin", { + easing: theme.transitions.easing.easeOut, + duration: theme.transitions.duration.enteringScreen, }), + marginLeft: 0, }), -); +})); + +const Alert = React.forwardRef(function Alert(props, ref) { + return ; +}); const AppBar = styled(MuiAppBar, { - shouldForwardProp: (prop) => prop !== 'open', + shouldForwardProp: (prop) => prop !== "open", })(({ theme, open }) => ({ - transition: theme.transitions.create(['margin', 'width'], { + transition: theme.transitions.create(["margin", "width"], { easing: theme.transitions.easing.sharp, duration: theme.transitions.duration.leavingScreen, }), ...(open && { width: `calc(100% - ${drawerWidth}px)`, marginLeft: `${drawerWidth}px`, - transition: theme.transitions.create(['margin', 'width'], { + transition: theme.transitions.create(["margin", "width"], { easing: theme.transitions.easing.easeOut, duration: theme.transitions.duration.enteringScreen, }), }), })); -const DrawerHeader = styled('div')(({ theme }) => ({ - display: 'flex', - alignItems: 'center', +const DrawerHeader = styled("div")(({ theme }) => ({ + display: "flex", + alignItems: "center", padding: theme.spacing(0, 1), // necessary for content to be below app bar ...theme.mixins.toolbar, - justifyContent: 'flex-end', + justifyContent: "flex-end", })); +let counter, currentcounter; function PersistentDrawerLeft(props) { - const location = useLocation() - const navigate = useNavigate() + const location = useLocation(); + + const navigate = useNavigate(); const theme = useTheme(); const [open, setOpen] = React.useState(false); + const [openSnack, setSnack] = React.useState(false); + + //for snackbar functionalties + + const handleClose = (event, reason) => { + if (reason === "clickaway") { + return; + } + + setSnack(false); + }; + const handleClick = () => { + setSnack(false); + setSnack(true); + }; + + //counting cart items + counter = localStorage.getItem("carts"); + if (counter) { + currentcounter = JSON.parse(counter); + } else { + currentcounter = []; + } const [anchorElUser, setAnchorElUser] = React.useState(null); @@ -100,93 +131,136 @@ function PersistentDrawerLeft(props) { }; const logout = () => { - localStorage.removeItem(TOKEN_KEY) - navigate('/login') - handleCloseUserMenu() - } - useEffect(() => { - - }, []) + localStorage.removeItem(TOKEN_KEY); + navigate("/login"); + handleCloseUserMenu(); + }; + useEffect(() => {}, []); const renderContent = (routeName) => { - console.log(routeName) + console.log(routeName); switch (routeName) { - case '/login': - return - case '/products': - return - case '/dashboard': - return - case '/categories': - return + case "/login": + return ; + case "/products": + return ; + case "/dashboard": + return ; + case "/categories": + return ; + case "/CartPage": + return ; } - } + }; const handleOpenUserMenu = (event) => { setAnchorElUser(event.currentTarget); }; const handleCloseUserMenu = () => { setAnchorElUser(null); }; + //check if logged in + const [isLogged, setIsLogged] = React.useState(true); + useEffect(() => { + console.log("1"); + let token; + try { + token = JSON.parse(localStorage.getItem("token")); + console.log("2"); + if (!token) setIsLogged(false); + } catch (error) { + console.log(error); + setIsLogged(false); + } + }, [isLogged]); + if (!isLogged) return ; return ( - + - - - + + - - - - - - - - - + + + + + + + + + + + + + + + - + Logout - - {theme.direction === 'ltr' ? : } + {theme.direction === "ltr" ? : } - + - + - + - + - + - + - + - + @@ -233,8 +307,13 @@ function PersistentDrawerLeft(props) { {renderContent(location.pathname)} + + + Product has been sent to cart + + ); } -export default PersistentDrawerLeft \ No newline at end of file +export default PersistentDrawerLeft; diff --git a/src/components/Inputs.jsx b/src/components/Inputs.jsx new file mode 100644 index 0000000..c60c524 --- /dev/null +++ b/src/components/Inputs.jsx @@ -0,0 +1,15 @@ +import React from "react"; +import TextField from "@mui/material/TextField"; +export default function Inputs(props) { + return ( + + ); +} diff --git a/src/components/ProductCard.jsx b/src/components/ProductCard.jsx new file mode 100644 index 0000000..0bee2ad --- /dev/null +++ b/src/components/ProductCard.jsx @@ -0,0 +1,112 @@ +import * as React from "react"; +import { useEffect } from "react"; +import Card from "@mui/material/Card"; +import CardActions from "@mui/material/CardActions"; +import CardContent from "@mui/material/CardContent"; +import CardMedia from "@mui/material/CardMedia"; +import Button from "@mui/material/Button"; +import Typography from "@mui/material/Typography"; +import Box from "@mui/material/Box"; +import { experimentalStyled as styled } from "@mui/material/styles"; +import Paper from "@mui/material/Paper"; +import Grid from "@mui/material/Grid"; +import { useLocation } from "react-router-dom"; +import { palette } from "@mui/system"; + +const Item = styled(Paper)(({ theme }) => ({ + ...theme.typography.body2, + padding: theme.spacing(2), + textAlign: "center", + color: theme.palette.text.secondary, +})); + +export default function ImgMediaCard(props) { + let button_text = "Send to Cart"; + let location = useLocation(); + switch (location.pathname) { + case "/product": + button_text = "Send to Cart"; + case "/CartPage": + button_text = "Remove"; + } + return ( + + + + + + + {props.product.title} + + + + ${props.product.price} + + + + + + + + + ); +} diff --git a/src/index.js b/src/index.js index bb29a24..f652b30 100644 --- a/src/index.js +++ b/src/index.js @@ -1,34 +1,33 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import './index.css'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; -import {BrowserRouter} from 'react-router-dom' -import Drawer from './components/Drawer' -import { createTheme, ThemeProvider, styled } from '@mui/material/styles'; +import React from "react"; +import ReactDOM from "react-dom"; +import "./index.css"; +import App from "./App"; +import reportWebVitals from "./reportWebVitals"; +import { BrowserRouter } from "react-router-dom"; +import Drawer from "./components/Drawer"; +import { createTheme, ThemeProvider, styled } from "@mui/material/styles"; const theme = createTheme({ - palette: { - type: 'light', + type: "light", primary: { - main: '#000000', + main: "#101820FF", }, secondary: { - main: '#f50057', + main: "#006B38FF", }, }, -}) +}); ReactDOM.render( - - + + - - + + , - document.getElementById('root') + document.getElementById("root") ); // If you want to start measuring performance in your app, pass a function diff --git a/src/pages/CartPage.jsx b/src/pages/CartPage.jsx new file mode 100644 index 0000000..6676345 --- /dev/null +++ b/src/pages/CartPage.jsx @@ -0,0 +1,164 @@ +import React, { useEffect, useState } from "react"; + +import Button from "@mui/material/Button"; + +// import Product from "../components/Product"; +import Product from "../components/ProductCard"; + +import "../App.css"; +import Box from "@mui/material/Box"; +import Grid from "@mui/material/Grid"; +import Typography from "@mui/material/Typography"; + +let total; + +function CartPage(props) { + let sum; + + //const to check if there is items in the cart + const [Cart, setCart] = useState(() => { + const localData = localStorage.getItem("carts"); + return localData ? JSON.parse(localData) : []; + }, []); + + //to remove item from cart + const onRemove = (product) => { + setCart(Cart.filter((item) => item.id != product.id)); + }; + useEffect(() => { + localStorage.setItem("carts", JSON.stringify(Cart)); + }, [Cart]); + + // find sum + sum = Cart.reduce((prev, current) => { + return prev + +current.price; + }, 0); + sum = (Math.round(sum * 100) / 100).toFixed(2); + + //find discount and total + let discount = sum / 2; + total = (Math.round((sum - discount) * 100) / 100).toFixed(2); + return ( + + {/* products in cart interface */} + + + {Cart.map((item, index) => { + return ; + })} + + + {/* cart details interface */} + + + + + Details + + + + {" "} + Items Number: + + + {Cart.length} + + + Total Price + + + {sum} $ + + + Discount + + + {discount} $ + + + + + Final Amount: + + {total} $ + + + + + + + + ); +} + +export default CartPage; diff --git a/src/pages/Dashboard.jsx b/src/pages/Dashboard.jsx index 3c13707..fe56732 100644 --- a/src/pages/Dashboard.jsx +++ b/src/pages/Dashboard.jsx @@ -1,32 +1,7 @@ -import React, { useEffect, useState } from 'react'; -import {Navigate} from 'react-router-dom' +import React, { useEffect, useState } from "react"; +import { Navigate } from "react-router-dom"; function Dashboard(props) { - const [isLogged, setIsLogged] = React.useState(true) - useEffect(()=>{ - console.log('1') - let token; - try { - token = JSON.parse(localStorage.getItem('token')) - console.log('2') - if(!token) - setIsLogged(false) - - } catch (error) { - console.log(error) - setIsLogged(false) - } - - },[]) - console.log('3') - - if(!isLogged) - return - - return ( -
- Dashboard -
- ); + return
Dashboard
; } -export default Dashboard; \ No newline at end of file +export default Dashboard; diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index cf8b851..242772b 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -1,40 +1,39 @@ -import React from 'react'; -import { useNavigate } from 'react-router-dom'; -import axios from '../utils/axios' -import {TOKEN_KEY} from '../utils/Constants' +import React from "react"; +import { useNavigate } from "react-router-dom"; +import axios from "../utils/axios"; +import { TOKEN_KEY } from "../utils/Constants"; function Login(props) { - const navigate = useNavigate() - const [email, setEmail] = React.useState('') - const [password, setPassword] = React.useState('') + const navigate = useNavigate(); + const [username, setEmail] = React.useState(""); + const [password, setPassword] = React.useState(""); - const login = (e)=>{ - e.preventDefault() - axios.post('/api/academy/auth/login', - { - email:email, - password:password - } - ) - .then((response)=>{ - console.log(response) - let token = response.data.token.access_token; - let data = response.data; - localStorage.setItem(TOKEN_KEY, JSON.stringify(data)) - navigate('/dashboard') - }) - .catch((err)=>{ - console.log(err) - }) - } - return ( -
-
- setEmail(e.target.value)} type="email" /> - setPassword(e.target.value)} type="password" /> - -
-
- ); + const login = (e) => { + e.preventDefault(); + axios + .post("/auth/login", { + username: username, + password: password, + }) + .then((response) => { + console.log(response); + let token = response.data.token; + let data = response.data; + localStorage.setItem(TOKEN_KEY, JSON.stringify(data)); + navigate("/dashboard"); + }) + .catch((err) => { + console.log(err); + }); + }; + return ( +
+
+ setEmail(e.target.value)} type="username" /> + setPassword(e.target.value)} type="password" /> + +
+
+ ); } -export default Login; \ No newline at end of file +export default Login; diff --git a/src/pages/Products.jsx b/src/pages/Products.jsx index e3fcba4..2987755 100644 --- a/src/pages/Products.jsx +++ b/src/pages/Products.jsx @@ -1,12 +1,88 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from "react"; +import { TOKEN_KEY } from "../utils/Constants"; +import Inputs from "../components/Inputs"; + +import { Navigate } from "react-router-dom"; + +// import Product from "../components/Product"; +import Product from "../components/ProductCard"; +import axios from "../utils/axios"; +import "../App.css"; +import Box from "@mui/material/Box"; + +import Grid from "@mui/material/Grid"; function Products(props) { - - return ( -
- Products -
- ); + const [Products, setProducts] = useState([]); + const [search_value, setSearch] = useState(""); + const [items_filter, setFilter] = useState([]); + //check if cart already has products in local storage or just create new one + const [Cart, setCart] = useState(() => { + const localData = localStorage.getItem("carts"); + return localData ? JSON.parse(localData) : []; + }, []); + + //add product to cart + const onAdd = (product) => { + if (Cart.filter((item) => item.id === product.id) != "") { + return; + } + Cart.push(product); + setCart(Cart); + localStorage.setItem("carts", JSON.stringify(Cart)); + props.handleClick(); + }; + + //searching for products + function onSearchChange(e) { + let newValue = e.target.value; + let name = Products; + if (!newValue) { + setSearch(newValue); + setFilter([...Products]); + } + let filtered = name.filter((item) => { + return item.title.toLowerCase().includes(newValue.toLowerCase()); + }); + setSearch(newValue); + setFilter([...filtered]); + } + + //get products from the api + useEffect(() => { + axios + .get("/products") + .then((res) => { + setProducts(res.data); + setFilter(res.data); + }) + .catch((err) => { + console.log(err); + }); + }, [Products]); + + return ( + + + + {items_filter.map((item, index) => { + return ; + })} + + + ); } -export default Products; \ No newline at end of file +export default Products; diff --git a/src/utils/Constants.js b/src/utils/Constants.js index 1574da1..fda62ed 100644 --- a/src/utils/Constants.js +++ b/src/utils/Constants.js @@ -1,2 +1,2 @@ -export const TOKEN_KEY = 'token' -export const BASE_URL = 'https://website-backend.computiq.tech' \ No newline at end of file +export const TOKEN_KEY = "token"; +export const BASE_URL = "https://fakestoreapi.com";