diff --git a/backend/controllers/cartController.js b/backend/controllers/cartController.js
index c7c559f..293a559 100644
--- a/backend/controllers/cartController.js
+++ b/backend/controllers/cartController.js
@@ -12,20 +12,19 @@ const addToCart = async (req, res) => {
const cart = await Cart.findOne({ userId });
if (!cart) {
- const newCart = new Cart({
+ await Cart.create({
userId,
products: [{ product: productId, quantity: 1 }],
});
- await newCart.save();
return res.status(200).json({ message: "Producto añadido al carrito" });
}
- const productIndex = cart.products.findIndex(
- (p) => p.product.toString() === productId
+ const productInCart = cart.products.find(
+ (item) => item.product.toString() === productId
);
- if (productIndex !== -1) {
- cart.products[productIndex].quantity += 1;
+ if (productInCart) {
+ productInCart.quantity += 1;
} else {
cart.products.push({ product: productId, quantity: 1 });
}
@@ -40,7 +39,29 @@ const addToCart = async (req, res) => {
const removeFromCart = async (req, res) => {
try {
- } catch (error) {}
+ const userId = req.params.userid;
+ const productId = req.params.product;
+
+ const cart = await Cart.findOne({ userId });
+
+ const productInCart = cart.products.find(
+ (item) => item.product.toString() === productId
+ );
+
+ if (productInCart && productInCart.quantity > 1) {
+ productInCart.quantity -= 1;
+ } else if (productInCart.quantity <= 1) {
+ productInCart.deleteOne();
+ } else {
+ return res.json({ error: "No se ha podido eliminar el producto" });
+ }
+
+ await cart.save();
+
+ res.status(200).json({ message: "Producto eliminado" });
+ } catch (error) {
+ res.status(500).json({ error: "Error del servidor" });
+ }
};
const getCartProducts = async (req, res) => {
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index ac70b0e..b2091ce 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -17,6 +17,7 @@ import {
EmailVerification,
AdminDashboard,
AdminProducts,
+ Checkout,
} from "./Routes";
import axios from "axios";
import { Toaster } from "react-hot-toast";
@@ -60,6 +61,7 @@ export default function App() {
path="/admin-dashboard/products"
element={}
/>
+ } />
} />
diff --git a/frontend/src/Routes.js b/frontend/src/Routes.js
index 6986258..49d9dde 100644
--- a/frontend/src/Routes.js
+++ b/frontend/src/Routes.js
@@ -12,6 +12,7 @@ import EmailVerification from "./pages/error/EmailVerification.jsx";
import AdminDashboard from "./pages/admin/AdminDashboard.jsx";
import AdminProducts from "./pages/admin/AdminProducts.jsx";
import Product from "./pages/Product.jsx";
+import Checkout from "./pages/Checkout.jsx";
export {
Login,
@@ -27,5 +28,6 @@ export {
Error,
EmailVerification,
AdminDashboard,
- AdminProducts
+ AdminProducts,
+ Checkout
};
diff --git a/frontend/src/components/Footer.jsx b/frontend/src/components/Footer.jsx
index 02f663b..9ea2f7a 100644
--- a/frontend/src/components/Footer.jsx
+++ b/frontend/src/components/Footer.jsx
@@ -8,37 +8,29 @@ export default function Footer() {
const footer = (
- )
-
- return (
- <>
- {user && user.role !== 1 ? (
- footer
- ) : (
- footer
- )}
- >
+
+
+
+
);
+
+ return <>{user && user.role !== 1 ? footer :
}>;
}
diff --git a/frontend/src/components/NavbarLoggedIn.jsx b/frontend/src/components/NavbarLoggedIn.jsx
index 9c879b8..ff8e31a 100644
--- a/frontend/src/components/NavbarLoggedIn.jsx
+++ b/frontend/src/components/NavbarLoggedIn.jsx
@@ -12,24 +12,6 @@ import ShoppingCartComponent from "./ShoppingCartComponent";
export default function NavbarLoggedIn({ genres }) {
const navigate = useNavigate();
const { user, setUser } = useContext(UserContext);
- const { productAdded, setProductAdded } = useContext(CartContext);
- const [cartProducts, setCartProducts] = useState([]);
-
- useEffect(() => {
- if (user) {
- const fetchCartProducts = async () => {
- try {
- const response = await axios.get(`/get-cart-products/${user._id}`);
- if (!response.data.error) {
- setCartProducts(response.data);
- }
- } catch (error) {
- console.error(error);
- }
- };
- fetchCartProducts();
- }
- }, [user, productAdded]);
const logoutUser = async () => {
try {
@@ -136,7 +118,7 @@ export default function NavbarLoggedIn({ genres }) {
{/** Icono de busqueda (Queda mal en mobiles) */}
{/** Carrito de compra */}
- {user.role !== 1 && }
+ {user.role !== 1 && }
{/**Avatar desplegable */}
diff --git a/frontend/src/components/ShoppingCartComponent.jsx b/frontend/src/components/ShoppingCartComponent.jsx
index 0109cfe..714a39e 100644
--- a/frontend/src/components/ShoppingCartComponent.jsx
+++ b/frontend/src/components/ShoppingCartComponent.jsx
@@ -1,54 +1,28 @@
import { Link } from "react-router-dom";
-import { memo, useState, useEffect } from "react";
+import { memo, useState, useEffect, useContext } from "react";
+import { UserContext } from "../context/userContext";
+import { CartContext } from "../context/cartContext";
import axios from "axios";
+import toast from "react-hot-toast";
-const ShoppingCartComponent = ({ cartProducts }) => {
- const [products, setProducts] = useState([]);
- const [totalPrice, setTotalPrice] = useState(0);
- const [quantity, setQuantity] = useState(0);
+const ShoppingCartComponent = () => {
+ const { user } = useContext(UserContext);
+ const { setCartChanged, products, quantity, totalPrice } =
+ useContext(CartContext);
- useEffect(() => {
- console.log("Cart Products:", cartProducts);
+ const deleteCartProduct = async (productId) => {
+ try {
+ const response = await axios.delete(
+ `/remove-from-cart/${user._id}/${productId}`
+ );
- if (!Array.isArray(cartProducts)) {
- console.error("cartProducts is not an array:", cartProducts);
- return;
- }
-
- const getProducts = async () => {
- try {
- const productDetails = await Promise.all(
- cartProducts.map(async (cartProduct) => {
- const response = await axios.get(
- `/get-product/${cartProduct.product}`
- );
- return { ...response.data, quantity: cartProduct.quantity };
- })
- );
-
- setProducts(productDetails);
-
- const totalQuantity = productDetails.reduce(
- (acc, product) => acc + product.quantity,
- 0
- );
- setQuantity(totalQuantity);
-
- const total = productDetails.reduce(
- (acc, curr) => acc + Number(curr.price) * curr.quantity,
- 0
- );
- setTotalPrice(total);
- } catch (error) {
- console.error(error);
+ if (!response.data.error) {
+ toast.success(response.data.message);
+ setCartChanged((val) => !val);
+ } else {
+ toast.error(response.data.error);
}
- };
-
- getProducts();
- }, [cartProducts]);
-
- const deleteCartProduct = (productId) => {
- // Lógica para eliminar el producto del carrito
+ } catch (error) {}
};
return (
diff --git a/frontend/src/context/cartContext.jsx b/frontend/src/context/cartContext.jsx
index 1215b70..8132d0c 100644
--- a/frontend/src/context/cartContext.jsx
+++ b/frontend/src/context/cartContext.jsx
@@ -1,14 +1,76 @@
-import { createContext, useState } from "react";
+import { createContext, useState, useEffect, useContext } from "react";
+import { UserContext } from "./userContext";
+import axios from "axios";
-export const CartContext = createContext({
- productAdded: false,
- setProductAdded: () => {},
-});
+export const CartContext = createContext({});
export function CartContextProvider({ children }) {
- const [productAdded, setProductAdded] = useState(false);
+ const [cartChanged, setCartChanged] = useState(false);
+ const [cartProducts, setCartProducts] = useState([]);
+ const { user } = useContext(UserContext);
+ const [products, setProducts] = useState([]);
+ const [totalPrice, setTotalPrice] = useState(0);
+ const [quantity, setQuantity] = useState(0);
+
+ useEffect(() => {
+ if (user) {
+ const fetchCartProducts = async () => {
+ try {
+ const response = await axios.get(`/get-cart-products/${user._id}`);
+ if (!response.data.error) {
+ setCartProducts(response.data);
+ }
+ } catch (error) {
+ console.error(error);
+ }
+ };
+ fetchCartProducts();
+ }
+ }, [user, cartChanged]);
+
+ useEffect(() => {
+ const getProducts = async () => {
+ try {
+ const productDetails = await Promise.all(
+ cartProducts.map(async (cartProduct) => {
+ const response = await axios.get(
+ `/get-product/${cartProduct.product}`
+ );
+ return { ...response.data, quantity: cartProduct.quantity };
+ })
+ );
+
+ setProducts(productDetails);
+
+ const totalQuantity = productDetails.reduce(
+ (acc, product) => acc + product.quantity,
+ 0
+ );
+ setQuantity(totalQuantity);
+
+ const total = productDetails.reduce(
+ (acc, curr) => acc + Number(curr.price) * curr.quantity,
+ 0
+ );
+ setTotalPrice(total);
+ } catch (error) {
+ console.error(error);
+ }
+ };
+
+ getProducts();
+ }, [cartProducts]);
+
return (
-
+
{children}
);
diff --git a/frontend/src/pages/Cart.jsx b/frontend/src/pages/Cart.jsx
index 0bfa435..01a4cbe 100644
--- a/frontend/src/pages/Cart.jsx
+++ b/frontend/src/pages/Cart.jsx
@@ -1,7 +1,134 @@
-import React from 'react'
+import { useContext } from "react";
+import { UserContext } from "../context/userContext";
+import { CartContext } from "../context/cartContext";
+import { Link } from "react-router-dom";
+import Error from "./error/Error";
+import axios from "axios";
+import toast from "react-hot-toast";
export default function Cart() {
+ const { user } = useContext(UserContext);
+ const { setCartChanged, products, quantity, totalPrice } =
+ useContext(CartContext);
+
+ const deleteCartProduct = async (productId) => {
+ try {
+ const response = await axios.delete(
+ `/remove-from-cart/${user._id}/${productId}`
+ );
+
+ if (!response.data.error) {
+ toast.success(response.data.message);
+ setCartChanged((val) => !val);
+ } else {
+ toast.error(response.data.error);
+ }
+ } catch (error) {
+ toast.error("Error del servidor");
+ }
+ };
+
+ const addCartProduct = async (productId) => {
+ try {
+ const response = await axios.post(
+ `/add-to-cart/${user._id}/${productId}`
+ );
+ if (!response.data.error) {
+ toast.success(response.data.message);
+ setCartChanged((val) => !val);
+ } else {
+ toast.error(response.data.error);
+ }
+ } catch (error) {
+ toast.error("Error del servidor");
+ }
+ };
+
return (
- Cart
- )
+ <>
+ {user ? (
+
+
{quantity} Productos
+ {products ? (
+ products?.map((product) => (
+
+
+

+
+
{product.productName}
+
{product.description}
+
+
+
+ {/** Boton restar */}
+
+
{product.quantity}
+ {/** Boton sumar */}
+
+
+
{product.price}€
+
+
+
+ ))
+ ) : (
+
No hay productos
+ )}
+
+
Total:
+
{totalPrice.toFixed(2)}€
+
+
+
+
+
+
+ ) : (
+
+ )}
+ >
+ );
}
diff --git a/frontend/src/pages/Checkout.jsx b/frontend/src/pages/Checkout.jsx
new file mode 100644
index 0000000..2403673
--- /dev/null
+++ b/frontend/src/pages/Checkout.jsx
@@ -0,0 +1,141 @@
+import { useState, useContext } from "react";
+import { CartContext } from "../context/cartContext";
+import TextBoxWithTextOnTop from "../components/TextBoxWithTextOnTop";
+
+export default function Checkout() {
+ const { totalPrice } = useContext(CartContext);
+ const [paymentMethod, setPaymentMethod] = useState("card");
+
+ const handlePaymentMethodChange = (e) => {
+ setPaymentMethod(e.target.value);
+ };
+
+ return (
+
+
+
+
+
+
+ Detalles de envio
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Resumen del pedido
+
+
+
+
+ Total productos
+
+ {totalPrice.toFixed(2)}€
+
+
+
+ Envío
+ 0.00€
+
+
+
+ Total
+ {totalPrice.toFixed(2)}€
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/pages/Product.jsx b/frontend/src/pages/Product.jsx
index 9851cda..ea44f2a 100644
--- a/frontend/src/pages/Product.jsx
+++ b/frontend/src/pages/Product.jsx
@@ -10,9 +10,9 @@ import StarRating from "../components/StarRating";
export default function Product() {
const { user } = useContext(UserContext);
- const { productAdded, setProductAdded } = useContext(CartContext);
+ const { setCartChanged } = useContext(CartContext);
const location = useLocation();
- const product = location.state.product;
+ const product = location.state?.product;
const addToCart = async () => {
try {
@@ -23,7 +23,7 @@ export default function Product() {
toast.error(response.data.error);
} else {
toast.success(response.data.message);
- setProductAdded((val) => !val);
+ setCartChanged((val) => !val);
}
} catch (error) {
toast.error(error.response.data.error);