diff --git a/package.json b/package.json index b7d4c1d1d4..c0ff21dd03 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ "type": "module", "scripts": { "dev": "vite", + "predeploy": "npm run build", + "deploy": "gh-pages -d dist", "build": "vite build", "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "preview": "vite build; vite preview --host" diff --git a/src/CartItem.css b/src/CartItem.css index 66a6a4061f..dc58987c4f 100644 --- a/src/CartItem.css +++ b/src/CartItem.css @@ -240,4 +240,96 @@ transition: background-color 0.3s ease; margin-top: 40px; } - \ No newline at end of file + .cart-container { + max-width: 800px; + margin: auto; + padding: 20px; +} + +.cart-item { + display: flex; + border: 1px solid #ddd; + border-radius: 8px; + margin-bottom: 20px; + padding: 10px; + background-color: #fff; +} + +.cart-item-image { + width: 120px; + height: 120px; + object-fit: cover; + border-radius: 8px; +} + +.cart-item-details { + flex-grow: 1; + padding-left: 15px; +} + +.cart-item-name { + font-size: 18px; + font-weight: bold; + margin-bottom: 5px; +} + +.cart-item-cost, +.cart-item-total { + font-size: 16px; + margin-bottom: 10px; +} + +.cart-item-quantity { + display: flex; + align-items: center; + margin-bottom: 10px; +} + +.cart-item-button { + width: 30px; + height: 30px; + border: none; + background-color: #4CAF50; + color: white; + font-size: 18px; + cursor: pointer; + border-radius: 4px; +} + +.cart-item-button:hover { + background-color: #45a049; +} + +.cart-item-quantity-value { + margin: 0 10px; + font-size: 16px; +} + +.cart-item-delete { + background-color: #f44336; + color: white; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; +} + +.cart-item-delete:hover { + background-color: #d32f2f; +} + +.get-started-button, +.get-started-button1 { + background-color: #4CAF50; + color: white; + border: none; + padding: 10px 20px; + margin-top: 10px; + border-radius: 5px; + cursor: pointer; +} + +.get-started-button:hover, +.get-started-button1:hover { + background-color: #45a049; +} diff --git a/src/CartItem.jsx b/src/CartItem.jsx index e06317433f..fc9192f32c 100644 --- a/src/CartItem.jsx +++ b/src/CartItem.jsx @@ -1,68 +1,83 @@ +// CartItem.jsx import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { removeItem, updateQuantity } from './CartSlice'; import './CartItem.css'; -const CartItem = ({ onContinueShopping }) => { - const cart = useSelector(state => state.cart.items); - const dispatch = useDispatch(); +const CartItem = ({ onContinueShopping, onRemoveFromCart }) => { + const cart = useSelector(state => state.cart.items); + const dispatch = useDispatch(); - // Calculate total amount for all products in the cart - const calculateTotalAmount = () => { - - }; + const calculateTotalAmount = () => { + return cart.reduce((total, item) => { + const cost = parseFloat(item.cost.replace('$', '')) || 0; + return total + cost * item.quantity; + }, 0).toFixed(2); + }; - const handleContinueShopping = (e) => { - - }; + const calculateTotalCost = (item) => { + const cost = parseFloat(item.cost.replace('$', '')) || 0; + return (cost * item.quantity).toFixed(2); + }; + const handleContinueShopping = (e) => { + onContinueShopping(e); + }; + const handleIncrement = (item) => { + dispatch(updateQuantity({ + name: item.name, + quantity: item.quantity + 1 + })); + }; - const handleIncrement = (item) => { - }; + const handleDecrement = (item) => { + if (item.quantity > 1) { + dispatch(updateQuantity({ + name: item.name, + quantity: item.quantity - 1 + })); + } + }; - const handleDecrement = (item) => { - - }; + const handleRemove = (item) => { + dispatch(removeItem(item.name)); + onRemoveFromCart(item.name); + }; - const handleRemove = (item) => { - }; + const handleCheckoutShopping = () => { + alert('Checkout functionality to be added in the future.'); + }; - // Calculate total cost based on quantity for an item - const calculateTotalCost = (item) => { - }; + return ( +
+

Total Cart Amount: ${calculateTotalAmount()}

+
+ {cart.map(item => ( +
+ {item.name} +
+
{item.name}
+
Cost: {item.cost}
+
+ + {item.quantity} + +
+
Total: ${calculateTotalCost(item)}
+ +
+
+ ))} +
- return ( -
-

Total Cart Amount: ${calculateTotalAmount()}

-
- {cart.map(item => ( -
- {item.name} -
-
{item.name}
-
{item.cost}
-
- - {item.quantity} - -
-
Total: ${calculateTotalCost(item)}
- +
+ +
+
-
- ))} -
-
-
- -
- -
-
- ); +
+ ); }; export default CartItem; - - diff --git a/src/CartSlice.jsx b/src/CartSlice.jsx index 32b8761ed0..e39490c556 100644 --- a/src/CartSlice.jsx +++ b/src/CartSlice.jsx @@ -1,21 +1,32 @@ +// CartSlice.js import { createSlice } from '@reduxjs/toolkit'; export const CartSlice = createSlice({ - name: 'cart', - initialState: { - items: [], // Initialize items as an empty array - }, - reducers: { - addItem: (state, action) => { - + name: 'cart', + initialState: { + items: [], }, - removeItem: (state, action) => { + reducers: { + addItem: (state, action) => { + const { name, image, cost } = action.payload; + const existingItem = state.items.find(item => item.name === name); + if (existingItem) { + existingItem.quantity++; + } else { + state.items.push({ name, image, cost, quantity: 1 }); + } + }, + removeItem: (state, action) => { + state.items = state.items.filter(item => item.name !== action.payload); + }, + updateQuantity: (state, action) => { + const { name, quantity } = action.payload; + const itemToUpdate = state.items.find(item => item.name === name); + if (itemToUpdate) { + itemToUpdate.quantity = quantity; + } + }, }, - updateQuantity: (state, action) => { - - - }, - }, }); export const { addItem, removeItem, updateQuantity } = CartSlice.actions; diff --git a/src/ProductList.css b/src/ProductList.css index 52f9c7a84f..1db451360c 100644 --- a/src/ProductList.css +++ b/src/ProductList.css @@ -39,14 +39,6 @@ body { } -/* Product Grid */ -.product-grid { - display:flex; - flex-direction: column; - width: 100vw; - align-items: center; - justify-content: center; -} .product-list { display: flex; flex-wrap: wrap; @@ -249,4 +241,104 @@ body { .ul div { text-align: center; /* Align text to the center */ } - } \ No newline at end of file + } + .plant-container { + padding: 20px; + max-width: 1200px; + margin: auto; +} + +.category-title { + margin-bottom: 15px; + font-size: 24px; + color: #333; +} + +/* .product-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 20px; +} */ + +.plant-card { + background-color: #fff; + border: 1px solid #ddd; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 4px 8px rgba(0,0,0,0.1); + transition: transform 0.2s ease; +} + +.plant-card:hover { + transform: scale(1.05); +} + +.plant-image { + width: 100%; + height: 180px; + object-fit: cover; +} + +.plant-info { + padding: 15px; +} + +.plant-name { + font-size: 18px; + margin: 0 0 10px; +} + +.plant-description { + font-size: 14px; + color: #555; + margin-bottom: 10px; +} + +.plant-cost { + font-size: 16px; + margin-bottom: 10px; +} + +.add-to-cart { + background-color: #4CAF50; + color: white; + border: none; + padding: 10px 15px; + border-radius: 5px; + cursor: pointer; + font-weight: bold; + transition: background-color 0.2s ease; +} + +.add-to-cart:hover { + background-color: #45a049; +} + +.cartNumber { + position: absolute; + top: 23px; + right: 20px; + color: white; + border-radius: 50%; + width: 22px; + height: 20px; + display: flex ; + align-items: center; + justify-content: center; + font-size: 24px; + font-weight: bold; +} + +.product-button:disabled { + background-color: grey; + color: white; + pointer-events: none; + opacity: 0.7; + cursor: not-allowed; +} + +.centre +{ + display: flex; + justify-content: center; +} diff --git a/src/ProductList.jsx b/src/ProductList.jsx index 7682c04fc4..f51b10a60f 100644 --- a/src/ProductList.jsx +++ b/src/ProductList.jsx @@ -1,9 +1,24 @@ import React, { useState, useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; import './ProductList.css' import CartItem from './CartItem'; +import { addItem } from './CartSlice'; + function ProductList({ onHomeClick }) { + const dispatch = useDispatch(); // Initialize dispatch + const cart = useSelector(state => state.cart.items); // Access cart from Redux const [showCart, setShowCart] = useState(false); - const [showPlants, setShowPlants] = useState(false); // State to control the visibility of the About Us page + const [addedToCart, setAddedToCart] = useState({}); + const [showPlants, setShowPlants] = useState(true); + + const handleAddToCart = (product) => { + dispatch(addItem(product)); + setAddedToCart(prevState => ({ + ...prevState, + [product.name]: true + })); + }; + const plantsArray = [ { @@ -240,18 +255,32 @@ function ProductList({ onHomeClick }) { const handleCartClick = (e) => { e.preventDefault(); - setShowCart(true); // Set showCart to true when cart icon is clicked + setShowCart(true); + setShowPlants(false); }; const handlePlantsClick = (e) => { e.preventDefault(); - setShowPlants(true); // Set showAboutUs to true when "About Us" link is clicked - setShowCart(false); // Hide the cart when navigating to About Us + setShowPlants(true); + setShowCart(false); }; const handleContinueShopping = (e) => { e.preventDefault(); setShowCart(false); + setShowPlants(true); + }; + + + const handleRemoveFromCart = (productName) => { + setAddedToCart((prevState) => { + const newState = { ...prevState }; + delete newState[productName]; // Remove the product from the addedToCart state + return newState; + }); }; + + const totalItems = cart.reduce((total, item) => total + item.quantity, 0); + return (
@@ -269,17 +298,62 @@ function ProductList({ onHomeClick }) {
handlePlantsClick(e)} style={styleA}>Plants
-
handleCartClick(e)} style={styleA}>

+
+ handleCartClick(e)} style={styleA}> +
+

+ + + + + + +

+ + {totalItems} + +
+
+
- {!showCart ? ( + { + showPlants ? (
+
+ {plantsArray.map((category, index) => ( // Loop through each category in plantsArray +
{/* Unique key for each category div */} +

+
{category.category}
{/* Display the category name */} +

+
{/* Container for the list of plant cards */} + {category.plants.map((plant, plantIndex) => ( // Loop through each plant in the current category +
{/* Unique key for each plant card */} + {plant.name} +
{plant.name}
{/* Display plant name */} + {/* Display other plant details like description and cost */} +
{plant.description}
{/* Display plant description */} +
{plant.cost}
{/* Display plant cost */} - -
- ) : ( - - )} + +
+ ))} +
))} +
+ ) : showCart ? ( + + ):(
)} ); } diff --git a/vite.config.js b/vite.config.js index 4d190ae430..beeaed5cdc 100644 --- a/vite.config.js +++ b/vite.config.js @@ -3,6 +3,6 @@ import react from '@vitejs/plugin-react' // https://vitejs.dev/config/ export default defineConfig({ - base: "/shoppingreact", + base: "/e-plantShopping", plugins: [react()], })