- Timestamp:
- 09/08/22 12:38:24 (2 years ago)
- Branches:
- master
- Children:
- ee05663
- Parents:
- 717ceae
- Location:
- frontend
- Files:
-
- 8 added
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
frontend/package-lock.json
r717ceae r16237c4 28 28 "react-router-dom": "^6.3.0", 29 29 "react-scripts": "5.0.1", 30 "react-toastify": "^9.0.8", 30 31 "web-vitals": "^2.1.4" 31 32 } … … 14659 14660 } 14660 14661 }, 14662 "node_modules/react-toastify": { 14663 "version": "9.0.8", 14664 "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.0.8.tgz", 14665 "integrity": "sha512-EwM+teWt49HSHx+67qI08yLAW1zAsBxCXLCsUfxHYv1W7/R3ZLhrqKalh7j+kjgPna1h5LQMSMwns4tB4ww2yQ==", 14666 "dependencies": { 14667 "clsx": "^1.1.1" 14668 }, 14669 "peerDependencies": { 14670 "react": ">=16", 14671 "react-dom": ">=16" 14672 } 14673 }, 14661 14674 "node_modules/react-transition-group": { 14662 14675 "version": "4.4.5", … … 27673 27686 } 27674 27687 }, 27688 "react-toastify": { 27689 "version": "9.0.8", 27690 "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.0.8.tgz", 27691 "integrity": "sha512-EwM+teWt49HSHx+67qI08yLAW1zAsBxCXLCsUfxHYv1W7/R3ZLhrqKalh7j+kjgPna1h5LQMSMwns4tB4ww2yQ==", 27692 "requires": { 27693 "clsx": "^1.1.1" 27694 } 27695 }, 27675 27696 "react-transition-group": { 27676 27697 "version": "4.4.5", -
frontend/package.json
r717ceae r16237c4 24 24 "react-router-dom": "^6.3.0", 25 25 "react-scripts": "5.0.1", 26 "react-toastify": "^9.0.8", 26 27 "web-vitals": "^2.1.4" 27 28 }, -
frontend/src/App.js
r717ceae r16237c4 11 11 import CategoryScreen from "./screens/CategoryScreen"; 12 12 import SigninScreen from "./screens/SigninScreen"; 13 import { ToastContainer } from "react-toastify"; 14 import "react-toastify/dist/ReactToastify.css"; 15 import ShippingAddressScreen from "./screens/ShippingAddressScreen"; 16 import SignupScreen from "./screens/SignupScreen"; 17 import PaymentMethodScreen from "./screens/PaymentMethodScreen"; 18 import PlaceOrderScreen from "./screens/PlaceOrderScreen"; 19 import OrderScreen from "./screens/OrderScreen"; 20 import CardPaymentScreen from "./screens/CardPaymentScreen"; 21 import OrderHistoryScreen from "./screens/OrderHistoryScreen"; 13 22 14 23 function App() { … … 17 26 return ( 18 27 <BrowserRouter> 28 <ToastContainer position="bottom-center" limit={1} /> 19 29 <Header /> 20 30 … … 24 34 <Route path="/cart" element={<CartScreen />} /> 25 35 <Route path="/signin" element={<SigninScreen />} /> 36 <Route path="/signup" element={<SignupScreen />} /> 37 <Route path="/shipping" element={<ShippingAddressScreen />} /> 38 <Route path="/payment" element={<PaymentMethodScreen />} /> 39 <Route path="/placeorder" element={<PlaceOrderScreen />} /> 40 <Route path="placeorder/payment" element={<CardPaymentScreen />} /> 41 <Route path="/orderhistory" element={<OrderHistoryScreen />} /> 42 <Route path="/order/:id" element={<OrderScreen />} /> 26 43 <Route path="/products" element={<CategoryScreen />} /> 27 44 </Routes> -
frontend/src/Store.js
r717ceae r16237c4 4 4 5 5 const initialState = { 6 userInfo: localStorage.getItem("userInfo") 7 ? JSON.parse(localStorage.getItem("userInfo")) 8 : null, 6 9 cart: { 10 shippingAddress: localStorage.getItem("shippingAddress") 11 ? JSON.parse(localStorage.getItem("shippingAddress")) 12 : {}, 13 paymentMethod: localStorage.getItem("paymentMethod") 14 ? localStorage.getItem("paymentMethod") 15 : "", 7 16 cartItems: localStorage.getItem("cartItems") 8 17 ? JSON.parse(localStorage.getItem("cartItems")) … … 32 41 return { ...state, cart: { ...state.cart, cartItems } }; 33 42 } 43 case "CART_CLEAR": 44 return { ...state, cart: { ...state.cart, cartItems: [] } }; 45 case "USER_SIGNIN": 46 return { ...state, userInfo: action.payload }; 47 case "USER_SIGNOUT": 48 return { 49 ...state, 50 userInfo: null, 51 cart: { cartItems: [], shippingAddress: {}, paymentMethod: "" }, 52 }; 53 case "SAVE_SHIPPING_ADDRESS": 54 return { 55 ...state, 56 cart: { ...state.cart, shippingAddress: action.payload }, 57 }; 58 case "SAVE_PAYMENT_METHOD": 59 return { 60 ...state, 61 cart: { ...state.cart, paymentMethod: action.payload }, 62 }; 34 63 default: 35 64 return state; -
frontend/src/components/Header.js
r717ceae r16237c4 16 16 import ShoppingBasketIcon from "@mui/icons-material/ShoppingCart"; 17 17 import MenuIcon from "@mui/icons-material/Menu"; 18 import { Link } from "react-router-dom";18 import { Link, NavLink, useNavigate } from "react-router-dom"; 19 19 import logo2 from "../Images/logo2.png"; 20 20 import Badge from "react-bootstrap/Badge"; … … 22 22 import { Store } from "../Store"; 23 23 import { useContext } from "react"; 24 import NavDropdown from "react-bootstrap/NavDropdown"; 24 25 25 26 const toggleMenu = (event) => { 27 event.stopPropagation(); 26 28 let menu = document.querySelector(".mobile-menu-container"); 27 29 menu.classList.remove("hidden"); … … 30 32 31 33 const toggleSubMenu = (event) => { 34 event.stopPropagation(); 32 35 let menu = document.querySelector(".subDropdown"); 33 36 menu.classList.remove("hidden"); … … 68 71 69 72 function Header() { 70 const { state } = useContext(Store); 71 const { cart } = state; 73 const { state, dispatch: ctxDispatch } = useContext(Store); 74 const { cart, userInfo } = state; 75 const navigate = useNavigate(); 76 77 const signoutHandler = () => { 78 ctxDispatch({ type: "USER_SIGNOUT" }); 79 localStorage.removeItem("userInfo"); 80 localStorage.removeItem("shippingAddress"); 81 localStorage.removeItem("paymentMethod"); 82 }; 83 72 84 return ( 73 85 <div className="header"> … … 78 90 onClick={toggleMenu} 79 91 /> 80 <img className="header__icon" src={logo2} alt="logo"></img> 92 <img 93 className="header__icon" 94 src={logo2} 95 alt="logo" 96 onClick={() => { 97 navigate("/"); 98 }} 99 ></img> 81 100 </div> 82 101 <div className="mobile-menu-container hidden"> … … 85 104 </div> 86 105 <ul className="mobile-menu"> 87 <li>Почетна</li> 106 <Link 107 to="/" 108 style={{ textDecoration: "none", color: "black" }} 109 onClick={closeMenu} 110 > 111 <li>Почетна</li> 112 </Link> 88 113 <li onClick={toggleSubMenu} className="subMenu"> 89 114 Производи <ArrowDropDownIcon /> … … 492 517 <div className="header__right"> 493 518 <div className="header__buttons"> 494 <span> 495 <AccountCircleIcon className="header__login" fontSize="large" /> 496 <p>Најави се</p> 497 </span> 519 {userInfo ? ( 520 <NavDropdown 521 title={ 522 <span> 523 <AccountCircleIcon 524 className="header__login" 525 fontSize="large" 526 /> 527 <p>{userInfo.name}</p> 528 </span> 529 } 530 id="basic-nav-dropdown" 531 > 532 <NavDropdown.Item 533 onClick={() => { 534 navigate("/profile"); 535 }} 536 > 537 Профил 538 </NavDropdown.Item> 539 540 <NavDropdown.Item 541 onClick={() => { 542 navigate("/orderhistory"); 543 }} 544 > 545 Нарачки 546 </NavDropdown.Item> 547 548 <NavDropdown.Divider /> 549 <Link 550 className="drowdown-item" 551 to="#signout" 552 onClick={signoutHandler} 553 > 554 Одјави се 555 </Link> 556 </NavDropdown> 557 ) : ( 558 <Link 559 to={"/signin"} 560 className="link" 561 onClick={() => { 562 navigate("/orderhistory"); 563 }} 564 > 565 <span> 566 <AccountCircleIcon className="header__login" fontSize="large" /> 567 <p>Најави се</p> 568 </span> 569 </Link> 570 )} 571 498 572 <Link to="/cart" className="badgee"> 499 573 <span> -
frontend/src/index.css
r717ceae r16237c4 1 .checkout-steps > div { 2 border-bottom: 0.2rem solid #a0a0a0; 3 color: #a0a0a0; 4 } 5 6 .checkout-steps > div.active { 7 border-bottom: 0.2rem solid #f08000; 8 color: #f08000; 9 } -
frontend/src/screens/SigninScreen.js
r717ceae r16237c4 1 import Axios from "axios"; 1 2 import Container from "react-bootstrap/Container"; 2 3 import Form from "react-bootstrap/Form"; … … 4 5 import Button from "react-bootstrap/Button"; 5 6 import "../styles/SigninScreen.css"; 6 import React from "react"; 7 import { Link, useLocation } from "react-router-dom"; 7 import React, { useContext, useEffect, useState } from "react"; 8 import { Link, useLocation, useNavigate } from "react-router-dom"; 9 import { Store } from "../Store"; 10 import { toast } from "react-toastify"; 11 import { getError } from "../components/utils"; 8 12 9 13 function SigninScreen() { 14 const navigate = useNavigate(); 10 15 const { search } = useLocation(); 11 16 const redirectInUrl = new URLSearchParams(search).get("redirect"); 12 17 const redirect = redirectInUrl ? redirectInUrl : "/"; 18 19 const [email, setEmail] = useState(""); 20 const [password, setPassword] = useState(""); 21 22 const { state, dispatch: ctxDispatch } = useContext(Store); 23 const { userInfo } = state; 24 25 const submitHandler = async (e) => { 26 e.preventDefault(); 27 try { 28 const { data } = await Axios.post("/api/users/signin", { 29 email, 30 password, 31 }); 32 ctxDispatch({ type: "USER_SIGNIN", payload: data }); 33 localStorage.setItem("userInfo", JSON.stringify(data)); 34 navigate(redirect || "/"); 35 } catch (err) { 36 toast.error(getError(err)); 37 } 38 }; 39 40 useEffect(() => { 41 if (userInfo) { 42 navigate(redirect); 43 } 44 }, [navigate, redirect, userInfo]); 45 13 46 return ( 14 47 <div className="pageContainer"> … … 18 51 </Helmet> 19 52 <h1>Најави се</h1> 20 <Form className="formCointainer" >53 <Form className="formCointainer" onSubmit={submitHandler}> 21 54 <Form.Group controlId="email"> 22 55 <Form.Label>Email</Form.Label> 23 <Form.Control type="email" required /> 56 <Form.Control 57 type="email" 58 required 59 onChange={(e) => setEmail(e.target.value)} 60 /> 24 61 </Form.Group> 25 62 <Form.Group controlId="password"> 26 63 <Form.Label>Лозинка</Form.Label> 27 <Form.Control type="email" required /> 64 <Form.Control 65 type="password" 66 required 67 onChange={(e) => setPassword(e.target.value)} 68 /> 28 69 </Form.Group> 29 70 <div className="submitBtnContainer"> -
frontend/src/styles/Header.css
r717ceae r16237c4 6 6 margin: 0; 7 7 padding: 0; 8 margin-top: 10px; 8 9 height: 70px; 9 10 width: 100%; … … 200 201 } 201 202 203 #basic-nav-dropdown { 204 display: flex; 205 justify-content: center; 206 align-items: center; 207 } 208 202 209 @media only screen and (max-width: 1015px) { 203 210 .header__dropdown { -
frontend/src/styles/SigninScreen.css
r717ceae r16237c4 13 13 .formCointainer { 14 14 width: 400px; 15 } 16 17 .shipPC { 18 display: flex; 19 flex-direction: column; 20 justify-content: center; 21 align-items: center; 22 } 23 24 .shipPC .checkout-steps { 25 width: 70%; 15 26 } 16 27 … … 32 43 } 33 44 } 45 46 @media only screen and (max-width: 559px) { 47 .shipPC .checkout-steps { 48 width: 100%; 49 } 50 } 51 52 @media only screen and (max-width: 331px) { 53 .shipPC .checkout-steps { 54 display: none; 55 } 56 }
Note:
See TracChangeset
for help on using the changeset viewer.