fork download
  1. import "../styles/CartStyles.css";
  2. import React, { useState, useEffect } from "react";
  3. import Layout from "./../components/layout/Layout";
  4. import { useCart } from "../context/cart";
  5. import { useAuth } from "../context/auth";
  6. import { useNavigate } from "react-router-dom";
  7. import DropIn from "braintree-web-drop-in-react";
  8. import axios from "axios";
  9. import toast from "react-hot-toast";
  10. import useRazorpay from "react-razorpay";
  11.  
  12. const CartPage = () => {
  13. const [auth, setAuth] = useAuth();
  14. const [cart, setCart] = useCart();
  15. const [clientToken, setClientToken] = useState("");
  16. const [instance, setInstance] = useState("");
  17. const [loading, setLoading] = useState(false);
  18. const navigate = useNavigate();
  19. const [Razorpay, isLoaded] = useRazorpay();
  20.  
  21. // Total price calculation
  22. const totalPrice = () => {
  23. try {
  24. let total = 0;
  25. cart?.forEach((item) => {
  26. total += item.price ?? 0;
  27. });
  28. return total.toLocaleString("en-IN", {
  29. style: "currency",
  30. currency: "INR",
  31. });
  32. } catch (error) {
  33. console.log(error);
  34. return "Error calculating total price";
  35. }
  36. };
  37.  
  38. // Remove item from cart
  39. const removeCartItem = (pid) => {
  40. try {
  41. let myCart = [...cart];
  42. let index = myCart.findIndex((item) => item._id === pid);
  43. myCart.splice(index, 1);
  44. setCart(myCart);
  45. localStorage.setItem("cart", JSON.stringify(myCart));
  46. } catch (error) {
  47. console.log(error);
  48. }
  49. };
  50.  
  51. // Get payment gateway token
  52. const getToken = async () => {
  53. try {
  54. const { data } = await axios.get("/api/vl/product/braintree/token");
  55. setClientToken(data?.clientToken);
  56. } catch (error) {
  57. console.log(error);
  58. }
  59. };
  60.  
  61. useEffect(() => {
  62. getToken();
  63. }, [auth?.token]);
  64.  
  65. // Handle payments
  66. const handlePayment = async () => {
  67. try {
  68. setLoading(true);
  69. const { nonce } = await instance.requestPaymentMethod();
  70. const { data } = await axios.post("/api/vl/product/braintree/payment", {
  71. nonce,
  72. cart,
  73. });
  74. setLoading(false);
  75. localStorage.removeItem("cart");
  76. setCart([]);
  77. navigate("/dashboard/user/orders");
  78. toast.success("Payment Completed Successfully ");
  79. } catch (error) {
  80. console.log(error);
  81. setLoading(false);
  82. }
  83. };
  84.  
  85. return (
  86. <Layout>
  87. <div className="cart-page">
  88. <div className="cart-heading">
  89. <div className="row">
  90. <div className="col-md-12">
  91. <h1 className="Main-heading bg-light p-2 mb-1">
  92. <p className="Main-heading">
  93. {cart?.length
  94. ? `You Have ${cart.length} items in your cart ${
  95. auth?.token ? "" : "please login to checkout !"
  96. }`
  97. : " Your Cart Is Empty"}
  98. </p>
  99. </h1>
  100. </div>
  101. </div>
  102. </div>
  103. <div className="container">
  104. <div className="row">
  105. <div className="col-md-9">
  106. <div className="product-container">
  107. {cart?.map((p) => (
  108. <div className="product-card" key={p._id}>
  109. <img
  110. src={`${process.env.REACT_APP_BASE_URL}/api/vl/product/product-photo/${p._id}`}
  111. className="card-img-top"
  112. onClick={() => navigate(`/product/${p.slug}`)}
  113. alt={p.name}
  114. />
  115. <div className="product-details">
  116. <h3 className="product-name">{p.name}</h3>
  117. <div className="product-prices">
  118. <span className="discounted-price">
  119. {p.price?.toLocaleString("en-IN", {
  120. style: "currency",
  121. currency: "INR",
  122. })}
  123. </span>
  124. </div>
  125. <div className="cart-remove-btn">
  126. <button
  127. className="button btn "
  128. onClick={() => removeCartItem(p._id)}
  129. >
  130. Remove
  131. </button>
  132. </div>
  133. </div>
  134. </div>
  135. ))}
  136. </div>
  137. </div>
  138.  
  139. <div className="col-md-5 cart-summary ">
  140. <h2>Cart Summary</h2>
  141. <p>Total | Checkout | Payment</p>
  142. <hr />
  143. <h4>Total : {totalPrice()} </h4>
  144. {auth?.user?.address ? (
  145. <>
  146. <div className="mb-3">
  147. <h4>Current Address</h4>
  148. <h5>{auth?.user?.address}</h5>
  149. <button
  150. className="button btn-outline-warning"
  151. onClick={() => navigate("/dashboard/user/profile")}
  152. >
  153. Update Address
  154. </button>
  155. <br />
  156. <br />
  157. <button
  158. className="button btn-primary"
  159. onClick={() => {
  160. if (!cart?.length) {
  161. toast.error("Cart is empty");
  162. return;
  163. }
  164. var products = cart.reduce((acc, current) => {
  165. const existingProduct = acc.find(
  166. (item) => item.productId === current._id
  167. );
  168. if (!existingProduct) {
  169. acc.push({ productId: current._id, quantity: 1 });
  170. } else {
  171. existingProduct.quantity++;
  172. }
  173. return acc;
  174. }, []);
  175. var request_body = {
  176. userId: auth.user._id,
  177. products: products,
  178. };
  179. axios
  180. .post("/api/vl/order/create", request_body)
  181. .then((response) => {
  182. if (response.status === 200) {
  183. localStorage.removeItem("cart");
  184. setCart([]);
  185.  
  186. var options = {
  187. key: process.env.REACT_APP_RAZORPAY_KEY_ID,
  188. amount: response.data.amount,
  189. currency: response.data.currency,
  190. name: "Olfactors",
  191. description: "Olfactors Payment Page",
  192. order_id: response.data.order_id,
  193. handler: function (res) {
  194. console.log(res);
  195. },
  196. prefill: {
  197. name: auth.user.name,
  198. email: auth.user.email,
  199. contact: auth.user.phone,
  200. },
  201. };
  202. var rzp1 = new Razorpay(options);
  203. rzp1.on("payment.failed", function (response) {
  204. alert(response.error.code);
  205. alert(response.error.description);
  206. alert(response.error.source);
  207. alert(response.error.step);
  208. alert(response.error.reason);
  209. alert(response.error.metadata.order_id);
  210. alert(response.error.metadata.payment_id);
  211. });
  212. rzp1.open();
  213. } else {
  214. toast.error("Something went wrong");
  215. }
  216. });
  217. }}
  218. >
  219. Make Payment
  220. </button>
  221. </div>
  222. </>
  223. ) : (
  224. <div className="mb-3">
  225. {auth?.token ? (
  226. <button
  227. className="button "
  228. onClick={() => navigate("/dashboard/user/profile")}
  229. >
  230. Update Address
  231. </button>
  232. ) : (
  233. <button
  234. className="button"
  235. onClick={() =>
  236. navigate("/login", {
  237. state: "/cart",
  238. })
  239. }
  240. >
  241. Plase Login to checkout
  242. </button>
  243. )}
  244. </div>
  245. )}
  246. <div className="mt-2">
  247. {!clientToken || !auth?.token || !cart?.length ? (
  248. ""
  249. ) : (
  250. <>
  251. <DropIn
  252. options={{
  253. authorization: clientToken,
  254. paypal: {
  255. flow: "vault",
  256. },
  257. }}
  258. onInstance={(instance) => setInstance(instance)}
  259. />
  260.  
  261. <button
  262. className="btn btn-primary"
  263. onClick={handlePayment}
  264. disabled={loading || !instance || !auth?.user?.address}
  265. >
  266. {loading ? "Processing ...." : "Make Payment"}
  267. </button>
  268. </>
  269. )}
  270. </div>
  271. </div>
  272. </div>
  273. </div>
  274. </div>
  275. </Layout>
  276. );
  277. };
  278.  
  279. export default CartPage;
Success #stdin #stdout 0.03s 25712KB
stdin
Standard input is empty
stdout
import "../styles/CartStyles.css";
import React, { useState, useEffect } from "react";
import Layout from "./../components/layout/Layout";
import { useCart } from "../context/cart";
import { useAuth } from "../context/auth";
import { useNavigate } from "react-router-dom";
import DropIn from "braintree-web-drop-in-react";
import axios from "axios";
import toast from "react-hot-toast";
import useRazorpay from "react-razorpay";

const CartPage = () => {
  const [auth, setAuth] = useAuth();
  const [cart, setCart] = useCart();
  const [clientToken, setClientToken] = useState("");
  const [instance, setInstance] = useState("");
  const [loading, setLoading] = useState(false);
  const navigate = useNavigate();
  const [Razorpay, isLoaded] = useRazorpay();

  // Total price calculation
  const totalPrice = () => {
    try {
      let total = 0;
      cart?.forEach((item) => {
        total += item.price ?? 0;
      });
      return total.toLocaleString("en-IN", {
        style: "currency",
        currency: "INR",
      });
    } catch (error) {
      console.log(error);
      return "Error calculating total price";
    }
  };

  // Remove item from cart
  const removeCartItem = (pid) => {
    try {
      let myCart = [...cart];
      let index = myCart.findIndex((item) => item._id === pid);
      myCart.splice(index, 1);
      setCart(myCart);
      localStorage.setItem("cart", JSON.stringify(myCart));
    } catch (error) {
      console.log(error);
    }
  };

  // Get payment gateway token
  const getToken = async () => {
    try {
      const { data } = await axios.get("/api/vl/product/braintree/token");
      setClientToken(data?.clientToken);
    } catch (error) {
      console.log(error);
    }
  };

  useEffect(() => {
    getToken();
  }, [auth?.token]);

  // Handle payments
  const handlePayment = async () => {
    try {
      setLoading(true);
      const { nonce } = await instance.requestPaymentMethod();
      const { data } = await axios.post("/api/vl/product/braintree/payment", {
        nonce,
        cart,
      });
      setLoading(false);
      localStorage.removeItem("cart");
      setCart([]);
      navigate("/dashboard/user/orders");
      toast.success("Payment Completed Successfully ");
    } catch (error) {
      console.log(error);
      setLoading(false);
    }
  };

  return (
    <Layout>
      <div className="cart-page">
        <div className="cart-heading">
          <div className="row">
            <div className="col-md-12">
              <h1 className="Main-heading bg-light p-2 mb-1">
                <p className="Main-heading">
                  {cart?.length
                    ? `You Have ${cart.length} items in your cart ${
                        auth?.token ? "" : "please login to checkout !"
                      }`
                    : " Your Cart Is Empty"}
                </p>
              </h1>
            </div>
          </div>
        </div>
        <div className="container">
          <div className="row">
            <div className="col-md-9">
              <div className="product-container">
                {cart?.map((p) => (
                  <div className="product-card" key={p._id}>
                    <img
                      src={`${process.env.REACT_APP_BASE_URL}/api/vl/product/product-photo/${p._id}`}
                      className="card-img-top"
                      onClick={() => navigate(`/product/${p.slug}`)}
                      alt={p.name}
                    />
                    <div className="product-details">
                      <h3 className="product-name">{p.name}</h3>
                      <div className="product-prices">
                        <span className="discounted-price">
                          {p.price?.toLocaleString("en-IN", {
                            style: "currency",
                            currency: "INR",
                          })}
                        </span>
                      </div>
                      <div className="cart-remove-btn">
                        <button
                          className="button btn "
                          onClick={() => removeCartItem(p._id)}
                        >
                          Remove
                        </button>
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            </div>

            <div className="col-md-5 cart-summary ">
              <h2>Cart Summary</h2>
              <p>Total | Checkout | Payment</p>
              <hr />
              <h4>Total : {totalPrice()} </h4>
              {auth?.user?.address ? (
                <>
                  <div className="mb-3">
                    <h4>Current Address</h4>
                    <h5>{auth?.user?.address}</h5>
                    <button
                      className="button btn-outline-warning"
                      onClick={() => navigate("/dashboard/user/profile")}
                    >
                      Update Address
                    </button>
                    <br />
                    <br />
                    <button
                      className="button btn-primary"
                      onClick={() => {
                        if (!cart?.length) {
                          toast.error("Cart is empty");
                          return;
                        }
                        var products = cart.reduce((acc, current) => {
                          const existingProduct = acc.find(
                            (item) => item.productId === current._id
                          );
                          if (!existingProduct) {
                            acc.push({ productId: current._id, quantity: 1 });
                          } else {
                            existingProduct.quantity++;
                          }
                          return acc;
                        }, []);
                        var request_body = {
                          userId: auth.user._id,
                          products: products,
                        };
                        axios
                          .post("/api/vl/order/create", request_body)
                          .then((response) => {
                            if (response.status === 200) {
                              localStorage.removeItem("cart");
                              setCart([]);

                              var options = {
                                key: process.env.REACT_APP_RAZORPAY_KEY_ID,
                                amount: response.data.amount,
                                currency: response.data.currency,
                                name: "Olfactors",
                                description: "Olfactors Payment Page",
                                order_id: response.data.order_id,
                                handler: function (res) {
                                  console.log(res);
                                },
                                prefill: {
                                  name: auth.user.name,
                                  email: auth.user.email,
                                  contact: auth.user.phone,
                                },
                              };
                              var rzp1 = new Razorpay(options);
                              rzp1.on("payment.failed", function (response) {
                                alert(response.error.code);
                                alert(response.error.description);
                                alert(response.error.source);
                                alert(response.error.step);
                                alert(response.error.reason);
                                alert(response.error.metadata.order_id);
                                alert(response.error.metadata.payment_id);
                              });
                              rzp1.open();
                            } else {
                              toast.error("Something went wrong");
                            }
                          });
                      }}
                    >
                      Make Payment
                    </button>
                  </div>
                </>
              ) : (
                <div className="mb-3">
                  {auth?.token ? (
                    <button
                      className="button "
                      onClick={() => navigate("/dashboard/user/profile")}
                    >
                      Update Address
                    </button>
                  ) : (
                    <button
                      className="button"
                      onClick={() =>
                        navigate("/login", {
                          state: "/cart",
                        })
                      }
                    >
                      Plase Login to checkout
                    </button>
                  )}
                </div>
              )}
              <div className="mt-2">
                {!clientToken || !auth?.token || !cart?.length ? (
                  ""
                ) : (
                  <>
                    <DropIn
                      options={{
                        authorization: clientToken,
                        paypal: {
                          flow: "vault",
                        },
                      }}
                      onInstance={(instance) => setInstance(instance)}
                    />

                    <button
                      className="btn btn-primary"
                      onClick={handlePayment}
                      disabled={loading || !instance || !auth?.user?.address}
                    >
                      {loading ? "Processing ...." : "Make Payment"}
                    </button>
                  </>
                )}
              </div>
            </div>
          </div>
        </div>
      </div>
    </Layout>
  );
};

export default CartPage;