Changeset 16237c4 for frontend


Ignore:
Timestamp:
09/08/22 12:38:24 (2 years ago)
Author:
Nace Gjorgjievski <nace.gorgievski123@…>
Branches:
master
Children:
ee05663
Parents:
717ceae
Message:

Added Order Functionality

Location:
frontend
Files:
8 added
9 edited

Legend:

Unmodified
Added
Removed
  • frontend/package-lock.json

    r717ceae r16237c4  
    2828        "react-router-dom": "^6.3.0",
    2929        "react-scripts": "5.0.1",
     30        "react-toastify": "^9.0.8",
    3031        "web-vitals": "^2.1.4"
    3132      }
     
    1465914660      }
    1466014661    },
     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    },
    1466114674    "node_modules/react-transition-group": {
    1466214675      "version": "4.4.5",
     
    2767327686      }
    2767427687    },
     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    },
    2767527696    "react-transition-group": {
    2767627697      "version": "4.4.5",
  • frontend/package.json

    r717ceae r16237c4  
    2424    "react-router-dom": "^6.3.0",
    2525    "react-scripts": "5.0.1",
     26    "react-toastify": "^9.0.8",
    2627    "web-vitals": "^2.1.4"
    2728  },
  • frontend/src/App.js

    r717ceae r16237c4  
    1111import CategoryScreen from "./screens/CategoryScreen";
    1212import SigninScreen from "./screens/SigninScreen";
     13import { ToastContainer } from "react-toastify";
     14import "react-toastify/dist/ReactToastify.css";
     15import ShippingAddressScreen from "./screens/ShippingAddressScreen";
     16import SignupScreen from "./screens/SignupScreen";
     17import PaymentMethodScreen from "./screens/PaymentMethodScreen";
     18import PlaceOrderScreen from "./screens/PlaceOrderScreen";
     19import OrderScreen from "./screens/OrderScreen";
     20import CardPaymentScreen from "./screens/CardPaymentScreen";
     21import OrderHistoryScreen from "./screens/OrderHistoryScreen";
    1322
    1423function App() {
     
    1726  return (
    1827    <BrowserRouter>
     28      <ToastContainer position="bottom-center" limit={1} />
    1929      <Header />
    2030
     
    2434        <Route path="/cart" element={<CartScreen />} />
    2535        <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 />} />
    2643        <Route path="/products" element={<CategoryScreen />} />
    2744      </Routes>
  • frontend/src/Store.js

    r717ceae r16237c4  
    44
    55const initialState = {
     6  userInfo: localStorage.getItem("userInfo")
     7    ? JSON.parse(localStorage.getItem("userInfo"))
     8    : null,
    69  cart: {
     10    shippingAddress: localStorage.getItem("shippingAddress")
     11      ? JSON.parse(localStorage.getItem("shippingAddress"))
     12      : {},
     13    paymentMethod: localStorage.getItem("paymentMethod")
     14      ? localStorage.getItem("paymentMethod")
     15      : "",
    716    cartItems: localStorage.getItem("cartItems")
    817      ? JSON.parse(localStorage.getItem("cartItems"))
     
    3241      return { ...state, cart: { ...state.cart, cartItems } };
    3342    }
     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      };
    3463    default:
    3564      return state;
  • frontend/src/components/Header.js

    r717ceae r16237c4  
    1616import ShoppingBasketIcon from "@mui/icons-material/ShoppingCart";
    1717import MenuIcon from "@mui/icons-material/Menu";
    18 import { Link } from "react-router-dom";
     18import { Link, NavLink, useNavigate } from "react-router-dom";
    1919import logo2 from "../Images/logo2.png";
    2020import Badge from "react-bootstrap/Badge";
     
    2222import { Store } from "../Store";
    2323import { useContext } from "react";
     24import NavDropdown from "react-bootstrap/NavDropdown";
    2425
    2526const toggleMenu = (event) => {
     27  event.stopPropagation();
    2628  let menu = document.querySelector(".mobile-menu-container");
    2729  menu.classList.remove("hidden");
     
    3032
    3133const toggleSubMenu = (event) => {
     34  event.stopPropagation();
    3235  let menu = document.querySelector(".subDropdown");
    3336  menu.classList.remove("hidden");
     
    6871
    6972function 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
    7284  return (
    7385    <div className="header">
     
    7890          onClick={toggleMenu}
    7991        />
    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>
    81100      </div>
    82101      <div className="mobile-menu-container hidden">
     
    85104        </div>
    86105        <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>
    88113          <li onClick={toggleSubMenu} className="subMenu">
    89114            Производи <ArrowDropDownIcon />
     
    492517      <div className="header__right">
    493518        <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
    498572          <Link to="/cart" className="badgee">
    499573            <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  
     1import Axios from "axios";
    12import Container from "react-bootstrap/Container";
    23import Form from "react-bootstrap/Form";
     
    45import Button from "react-bootstrap/Button";
    56import "../styles/SigninScreen.css";
    6 import React from "react";
    7 import { Link, useLocation } from "react-router-dom";
     7import React, { useContext, useEffect, useState } from "react";
     8import { Link, useLocation, useNavigate } from "react-router-dom";
     9import { Store } from "../Store";
     10import { toast } from "react-toastify";
     11import { getError } from "../components/utils";
    812
    913function SigninScreen() {
     14  const navigate = useNavigate();
    1015  const { search } = useLocation();
    1116  const redirectInUrl = new URLSearchParams(search).get("redirect");
    1217  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
    1346  return (
    1447    <div className="pageContainer">
     
    1851        </Helmet>
    1952        <h1>Најави се</h1>
    20         <Form className="formCointainer">
     53        <Form className="formCointainer" onSubmit={submitHandler}>
    2154          <Form.Group controlId="email">
    2255            <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            />
    2461          </Form.Group>
    2562          <Form.Group controlId="password">
    2663            <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            />
    2869          </Form.Group>
    2970          <div className="submitBtnContainer">
  • frontend/src/styles/Header.css

    r717ceae r16237c4  
    66  margin: 0;
    77  padding: 0;
     8  margin-top: 10px;
    89  height: 70px;
    910  width: 100%;
     
    200201}
    201202
     203#basic-nav-dropdown {
     204  display: flex;
     205  justify-content: center;
     206  align-items: center;
     207}
     208
    202209@media only screen and (max-width: 1015px) {
    203210  .header__dropdown {
  • frontend/src/styles/SigninScreen.css

    r717ceae r16237c4  
    1313.formCointainer {
    1414  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%;
    1526}
    1627
     
    3243  }
    3344}
     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.