diff --git a/src/CartItem.jsx b/src/CartItem.jsx index e06317433f..5f38c2210f 100644 --- a/src/CartItem.jsx +++ b/src/CartItem.jsx @@ -4,63 +4,99 @@ import { removeItem, updateQuantity } from './CartSlice'; import './CartItem.css'; const CartItem = ({ onContinueShopping }) => { - const cart = useSelector(state => state.cart.items); - const dispatch = useDispatch(); - - // Calculate total amount for all products in the cart - const calculateTotalAmount = () => { - - }; - - const handleContinueShopping = (e) => { - - }; - - - - const handleIncrement = (item) => { - }; - - const handleDecrement = (item) => { - - }; - - const handleRemove = (item) => { - }; - - // Calculate total cost based on quantity for an item - const calculateTotalCost = (item) => { - }; - - return ( -
-

Total Cart Amount: ${calculateTotalAmount()}

-
- {cart.map(item => ( -
- {item.name} -
-
{item.name}
-
{item.cost}
-
- - {item.quantity} - -
-
Total: ${calculateTotalCost(item)}
- + const cart = useSelector(state => state.cart.items); + const dispatch = useDispatch(); + + + const parseItemCostToInteger = (itemCost) => { + /* + Remove currency symbol before multiplication. + Otherwise, NaN returned. + Improve in future: Use regex to remove all possible currency symbols? + */ + return parseInt(itemCost.replace('$', ''), 10); + }; + + // Calculate total amount for all products in the cart + const calculateTotalAmount = () => { + let totalCost = 0; + + cart.forEach((item) => { + const itemCost = parseItemCostToInteger(item.cost); + totalCost += itemCost * item.quantity; + }); + + return totalCost; + }; + + const handleContinueShopping = (e) => { + onContinueShopping(e); + }; + + const handleCheckoutShopping = (e) => { + alert('Functionality to be added for future reference'); + }; + + const handleIncrement = (item) => { + const updatedItem = { ...item }; + updatedItem.quantity++; + dispatch(updateQuantity(updatedItem)); + }; + + const handleDecrement = (item) => { + const updatedItem = { ...item }; + + if (updatedItem.quantity == 1) { + // Remove item if number of items gets decremented to 0 + dispatch(removeItem(updatedItem)); + } else { + updatedItem.quantity--; + dispatch(updateQuantity(updatedItem)); + } + }; + + const handleRemove = (item) => { + dispatch(removeItem(item)); + }; + + // Calculate total cost based on quantity for an item + const calculateTotalCost = (item) => { + let totalCost = 0; + const itemCost = parseItemCostToInteger(item.cost); + totalCost = item.quantity * itemCost; + + return totalCost; + }; + + 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..6b142d16fb 100644 --- a/src/CartSlice.jsx +++ b/src/CartSlice.jsx @@ -1,21 +1,49 @@ 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: [], // Initialize items as an empty array + numOfItems: 0 // Number of items multiplied by their quantity }, - removeItem: (state, action) => { - }, - updateQuantity: (state, action) => { - + reducers: { + addItem: (state, action) => { + const { name, image, cost } = action.payload; + const existingItem = state.items.find(item => item.name === name); + + if (existingItem) { + // In existing items, quantity is already added as property + existingItem.quantity++; + } else { + state.items.push({ name, image, cost, quantity: 1 }); + } + + state.numOfItems += 1; + }, + + removeItem: (state, action) => { + const { name, quantity } = action.payload; + state.items = state.items.filter(item => item.name !== name); + state.numOfItems -= quantity; + + // Just to be sure... I hate negative numbers + if (state.numOfItems < 0) { + state.numOfItems = 0; + } + }, + + updateQuantity: (state, action) => { + const { name, quantity } = action.payload; + const existingItem = state.items.find(item => item.name === name); + + if (existingItem) { + const differenceQuantity = quantity - existingItem.quantity; + state.numOfItems += differenceQuantity; + existingItem.quantity = quantity; + } + }, }, - }, }); export const { addItem, removeItem, updateQuantity } = CartSlice.actions; diff --git a/src/ProductList.jsx b/src/ProductList.jsx index 7682c04fc4..aff34b8495 100644 --- a/src/ProductList.jsx +++ b/src/ProductList.jsx @@ -1,287 +1,252 @@ -import React, { useState, useEffect } from 'react'; -import './ProductList.css' -import CartItem from './CartItem'; -function ProductList({ onHomeClick }) { - const [showCart, setShowCart] = useState(false); - const [showPlants, setShowPlants] = useState(false); // State to control the visibility of the About Us page +/* Reset some default styles */ +body, h1, ul { + margin: 0; + padding: 0; +} - const plantsArray = [ - { - category: "Air Purifying Plants", - plants: [ - { - name: "Snake Plant", - image: "https://cdn.pixabay.com/photo/2021/01/22/06/04/snake-plant-5939187_1280.jpg", - description: "Produces oxygen at night, improving air quality.", - cost: "$15" - }, - { - name: "Spider Plant", - image: "https://cdn.pixabay.com/photo/2018/07/11/06/47/chlorophytum-3530413_1280.jpg", - description: "Filters formaldehyde and xylene from the air.", - cost: "$12" - }, - { - name: "Peace Lily", - image: "https://cdn.pixabay.com/photo/2019/06/12/14/14/peace-lilies-4269365_1280.jpg", - description: "Removes mold spores and purifies the air.", - cost: "$18" - }, - { - name: "Boston Fern", - image: "https://cdn.pixabay.com/photo/2020/04/30/19/52/boston-fern-5114414_1280.jpg", - description: "Adds humidity to the air and removes toxins.", - cost: "$20" - }, - { - name: "Rubber Plant", - image: "https://cdn.pixabay.com/photo/2020/02/15/11/49/flower-4850729_1280.jpg", - description: "Easy to care for and effective at removing toxins.", - cost: "$17" - }, - { - name: "Aloe Vera", - image: "https://cdn.pixabay.com/photo/2018/04/02/07/42/leaf-3283175_1280.jpg", - description: "Purifies the air and has healing properties for skin.", - cost: "$14" - } - ] - }, - { - category: "Aromatic Fragrant Plants", - plants: [ - { - name: "Lavender", - image: "https://images.unsplash.com/photo-1611909023032-2d6b3134ecba?q=80&w=1074&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - description: "Calming scent, used in aromatherapy.", - cost: "$20" - }, - { - name: "Jasmine", - image: "https://images.unsplash.com/photo-1592729645009-b96d1e63d14b?q=80&w=1170&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - description: "Sweet fragrance, promotes relaxation.", - cost: "$18" - }, - { - name: "Rosemary", - image: "https://cdn.pixabay.com/photo/2019/10/11/07/12/rosemary-4541241_1280.jpg", - description: "Invigorating scent, often used in cooking.", - cost: "$15" - }, - { - name: "Mint", - image: "https://cdn.pixabay.com/photo/2016/01/07/18/16/mint-1126282_1280.jpg", - description: "Refreshing aroma, used in teas and cooking.", - cost: "$12" - }, - { - name: "Lemon Balm", - image: "https://cdn.pixabay.com/photo/2019/09/16/07/41/balm-4480134_1280.jpg", - description: "Citrusy scent, relieves stress and promotes sleep.", - cost: "$14" - }, - { - name: "Hyacinth", - image: "https://cdn.pixabay.com/photo/2019/04/07/20/20/hyacinth-4110726_1280.jpg", - description: "Hyacinth is a beautiful flowering plant known for its fragrant.", - cost: "$22" - } - ] - }, - { - category: "Insect Repellent Plants", - plants: [ - { - name: "oregano", - image: "https://cdn.pixabay.com/photo/2015/05/30/21/20/oregano-790702_1280.jpg", - description: "The oregano plants contains compounds that can deter certain insects.", - cost: "$10" - }, - { - name: "Marigold", - image: "https://cdn.pixabay.com/photo/2022/02/22/05/45/marigold-7028063_1280.jpg", - description: "Natural insect repellent, also adds color to the garden.", - cost: "$8" - }, - { - name: "Geraniums", - image: "https://cdn.pixabay.com/photo/2012/04/26/21/51/flowerpot-43270_1280.jpg", - description: "Known for their insect-repelling properties while adding a pleasant scent.", - cost: "$20" - }, - { - name: "Basil", - image: "https://cdn.pixabay.com/photo/2016/07/24/20/48/tulsi-1539181_1280.jpg", - description: "Repels flies and mosquitoes, also used in cooking.", - cost: "$9" - }, - { - name: "Lavender", - image: "https://images.unsplash.com/photo-1611909023032-2d6b3134ecba?q=80&w=1074&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - description: "Calming scent, used in aromatherapy.", - cost: "$20" - }, - { - name: "Catnip", - image: "https://cdn.pixabay.com/photo/2015/07/02/21/55/cat-829681_1280.jpg", - description: "Repels mosquitoes and attracts cats.", - cost: "$13" - } - ] - }, - { - category: "Medicinal Plants", - plants: [ - { - name: "Aloe Vera", - image: "https://cdn.pixabay.com/photo/2018/04/02/07/42/leaf-3283175_1280.jpg", - description: "Soothing gel used for skin ailments.", - cost: "$14" - }, - { - name: "Echinacea", - image: "https://cdn.pixabay.com/photo/2014/12/05/03/53/echinacea-557477_1280.jpg", - description: "Boosts immune system, helps fight colds.", - cost: "$16" - }, - { - name: "Peppermint", - image: "https://cdn.pixabay.com/photo/2017/07/12/12/23/peppermint-2496773_1280.jpg", - description: "Relieves digestive issues and headaches.", - cost: "$13" - }, - { - name: "Lemon Balm", - image: "https://cdn.pixabay.com/photo/2019/09/16/07/41/balm-4480134_1280.jpg", - description: "Calms nerves and promotes relaxation.", - cost: "$14" - }, - { - name: "Chamomile", - image: "https://cdn.pixabay.com/photo/2016/08/19/19/48/flowers-1606041_1280.jpg", - description: "Soothes anxiety and promotes sleep.", - cost: "$15" - }, - { - name: "Calendula", - image: "https://cdn.pixabay.com/photo/2019/07/15/18/28/flowers-4340127_1280.jpg", - description: "Heals wounds and soothes skin irritations.", - cost: "$12" - } - ] - }, - { - category: "Low Maintenance Plants", - plants: [ - { - name: "ZZ Plant", - image: "https://images.unsplash.com/photo-1632207691143-643e2a9a9361?q=80&w=464&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - description: "Thrives in low light and requires minimal watering.", - cost: "$25" - }, - { - name: "Pothos", - image: "https://cdn.pixabay.com/photo/2018/11/15/10/32/plants-3816945_1280.jpg", - description: "Tolerates neglect and can grow in various conditions.", - cost: "$10" - }, - { - name: "Snake Plant", - image: "https://cdn.pixabay.com/photo/2021/01/22/06/04/snake-plant-5939187_1280.jpg", - description: "Needs infrequent watering and is resilient to most pests.", - cost: "$15" - }, - { - name: "Cast Iron Plant", - image: "https://cdn.pixabay.com/photo/2017/02/16/18/04/cast-iron-plant-2072008_1280.jpg", - description: "Hardy plant that tolerates low light and neglect.", - cost: "$20" - }, - { - name: "Succulents", - image: "https://cdn.pixabay.com/photo/2016/11/21/16/05/cacti-1846147_1280.jpg", - description: "Drought-tolerant plants with unique shapes and colors.", - cost: "$18" - }, - { - name: "Aglaonema", - image: "https://cdn.pixabay.com/photo/2014/10/10/04/27/aglaonema-482915_1280.jpg", - description: "Requires minimal care and adds color to indoor spaces.", - cost: "$22" - } - ] - } - ]; - const styleObj = { - backgroundColor: '#4CAF50', - color: '#fff!important', - padding: '15px', - display: 'flex', - justifyContent: 'space-between', - alignIems: 'center', - fontSize: '20px', - } - const styleObjUl = { - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - width: '1100px', - } - const styleA = { - color: 'white', - fontSize: '30px', - textDecoration: 'none', - } +/* Set a background color */ +body { + font-family: Arial, sans-serif; + background-color: #f0f0f0; +} + +/* Navbar */ +.navbar { + background-color: #4CAF50; + color: #fff!important; + padding: 15px; + display: flex; + justify-content: space-between; + align-items: center; + font-size: 20px; +} + +.navbar .ul { + display: flex; + justify-content: space-between; + align-items: center; + width: 1100px; +} + +.navbar li { + margin-right: 30px; +} - const handleHomeClick = (e) => { - e.preventDefault(); - onHomeClick(); - }; +.navbar .ul div a { + color: white; + font-size: 30px; + text-decoration: none; + +} - const handleCartClick = (e) => { - e.preventDefault(); - setShowCart(true); // Set showCart to true when cart icon is clicked - }; - 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 - }; +/* Product Grid */ +.product-grid { + display:flex; + flex-direction: column; + width: 100vw; + align-items: center; + justify-content: center; +} +.product-list { + display: flex; + flex-wrap: wrap; + gap: 50px; + /* background-color: pink; */ + /* justify-content: space-between; */ + padding: 20px; + width: 100%; + align-items: center; + justify-content: center; +} - const handleContinueShopping = (e) => { - e.preventDefault(); - setShowCart(false); - }; - return ( -
-
-
-
- - handleHomeClick(e)}> -
-

Paradise Nursery

- Where Green Meets Serenity -
-
-
+/* Product Card */ +.product-card { + flex: 0 0 calc(33.33% - 20px); /* Adjust width for 3 cards per row with 20px gap */ + max-width: calc(26.33% - 20px); /* Adjust max-width for 3 cards per row with 20px gap */ + margin-bottom: 20px; + padding: 20px; + background-color: #fff; + border: 1px solid #ccc; + border-radius: 5px; + text-align: center; + position: relative; + + gap: 20px; +} -
-
-
handlePlantsClick(e)} style={styleA}>Plants
-
handleCartClick(e)} style={styleA}>

-
-
- {!showCart ? ( -
+/* Pseudo-classes - Hover effect on product button */ +.product-card:hover { + transform: scale(1.05); + transition: transform 0.3s ease-in-out; + z-index: 1; +} +.product-title { + font-weight: bold; + margin-bottom: 10px; +} -
- ) : ( - - )} -
- ); +.product-price { + color: #e74c3c; + font-size: 1.2rem; + margin-bottom: 10px; } -export default ProductList; +.product-image { + max-width: 100%; + height: 200px; /* Adjust height for better consistency */ +} + +.product-button { + background-color: #e74c3c; + color: #fff; + border: none; + padding: 10px 20px; + cursor: pointer; + transition: background-color 0.3s ease-in-out; + margin-top: 10px; +} + +.product-button:hover { + background-color: #c0392b; +} + +/* Pseudo-elements - Sale badge */ +.product-card::before { + content: "SALE"; + background-color: #e74c3c; + color: #fff; + position: absolute; + top: 0; + right: 0; + padding: 5px 10px; + border-radius: 0 0 0 5px; +} +.tag_home_link{ + display: flex; + /* background-color: red; */ + flex-direction: column; + align-items: center; + justify-content: center; + margin-left: 50px; + color: white; + text-decoration: none; + font-size: 20px; +} +.tag_home_link h3{ + font-size: 30px; +} +.tag a{ + text-decoration: none; +} +.tag { + width: 400px; + display: flex; + align-items: center; + justify-content: center; +} + +.tag img { + height: 70px; + width: 70px; + border-radius: 70%; + +} + +.luxury { + display: flex; + align-items: center; + justify-content: center; + width: 650px; + font-size: 19px; +} +.cart{ + color: white; + display: flex; +} +.cart_quantity_count{ + margin-top: 16px; + /* background-color: red; */ + margin-left: 27px; + position: absolute; + font-size: 29px; + +} +.plantname_heading{ + display: flex; + align-items: center; + justify-content: center; + /* background-color: yellow; */ +} +.plant_heading{ + width: 400px; + text-align: center; + margin: 20px; + border: 1px solid rgb(5, 4, 4); + border-left: none; + border-right: none; + + +} +/* Add Media Query for responsiveness */ +@media (max-width: 768px) { + .product-card { + flex: 1 1 calc(50% - 20px); /* Adjust width for 2 cards per row with 20px gap on smaller screens */ + max-width: calc(50% - 20px); /* Adjust max-width for 2 cards per row with 20px gap on smaller screens */ + } +} +/* ProductList.css */ + +.product-button { + background-color: #4CAF50; /* Green */ + border: none; + color: white; + padding: 10px 20px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin: 4px 2px; + transition-duration: 0.4s; + cursor: pointer; + } + + .product-button:hover { + background-color: #45a049; + } + + .product-button.added-to-cart { + background-color: grey; /* Grey when product is added */ + } + @media (max-width: 1200px) { + .product-card { + flex: 1 1 calc(33.33% - 20px); /* Adjust width for 3 cards per row with 20px gap on medium screens */ + max-width: calc(33.33% - 20px); /* Adjust max-width for 3 cards per row with 20px gap on medium screens */ + } + } + + @media (max-width: 768px) { + .product-card { + flex: 1 1 calc(50% - 20px); /* Adjust width for 2 cards per row with 20px gap on small screens */ + max-width: calc(50% - 20px); /* Adjust max-width for 2 cards per row with 20px gap on small screens */ + } + .navbar { + flex-direction: column; /* Change flex direction to stack items vertically */ + align-items: center; /* Align items to the center of the container */ + } + + .tag { + margin-bottom: 20px; /* Add margin bottom for spacing */ + text-align: center; /* Align text to the center */ + } + + .ul { + display: flex; /* Set display to flex */ + flex-direction: column; /* Change flex direction to stack items vertically */ + gap: 10px; /* Add gap between items */ + } + + .ul div { + text-align: center; /* Align text to the center */ + } + } diff --git a/src/store.js b/src/store.js index 54d0d6d66e..57a00db8c5 100644 --- a/src/store.js +++ b/src/store.js @@ -1,8 +1,9 @@ import { configureStore } from '@reduxjs/toolkit'; import cartReducer from './CartSlice'; + const store = configureStore({ reducer: { cart: cartReducer, }, }); -export default store +export default store \ No newline at end of file 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()], })