From bfec741503cfd3e8c4207ffac90bd7376a0df5dd Mon Sep 17 00:00:00 2001 From: Raulkumar <42264691+Raulkumar@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:04:17 +0530 Subject: [PATCH 1/2] e-plantshopping commit --- src/CartItem.jsx | 26 ++++++++++++++--- src/CartSlice.js | 40 ++++++++++++++++++++++++++ src/CartSlice.jsx | 26 ++--------------- src/ProductList.jsx | 68 ++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 126 insertions(+), 34 deletions(-) create mode 100644 src/CartSlice.js diff --git a/src/CartItem.jsx b/src/CartItem.jsx index e06317433f..1ad4b8e46a 100644 --- a/src/CartItem.jsx +++ b/src/CartItem.jsx @@ -1,4 +1,4 @@ -import React from 'react'; +/* eslint-disable react/prop-types */ import { useSelector, useDispatch } from 'react-redux'; import { removeItem, updateQuantity } from './CartSlice'; import './CartItem.css'; @@ -9,27 +9,45 @@ const CartItem = ({ onContinueShopping }) => { // Calculate total amount for all products in the cart const calculateTotalAmount = () => { - + // Sum over each item's subtotal (quantity * numeric cost) + return cart.reduce((sum, item) => { + const price = parseFloat(String(item.cost).replace(/[^0-9.]/g, '')) || 0; + const qty = item.quantity || 0; + return sum + price * qty; + }, 0).toFixed(2); }; const handleContinueShopping = (e) => { - + e.preventDefault(); + if (onContinueShopping) onContinueShopping(e); }; const handleIncrement = (item) => { + const newQty = (item.quantity || 0) + 1; + dispatch(updateQuantity({ name: item.name, quantity: newQty })); }; const handleDecrement = (item) => { - + const currentQty = item.quantity || 0; + if (currentQty > 1) { + dispatch(updateQuantity({ name: item.name, quantity: currentQty - 1 })); + } else { + // If quantity would drop to 0, remove the item from cart + dispatch(removeItem(item.name)); + } }; const handleRemove = (item) => { + dispatch(removeItem(item.name)); }; // Calculate total cost based on quantity for an item const calculateTotalCost = (item) => { + const price = parseFloat(String(item.cost).replace(/[^0-9.]/g, '')) || 0; + const qty = item.quantity || 0; + return (price * qty).toFixed(2); }; return ( diff --git a/src/CartSlice.js b/src/CartSlice.js new file mode 100644 index 0000000000..99b65dfcc9 --- /dev/null +++ b/src/CartSlice.js @@ -0,0 +1,40 @@ +import { createSlice } from '@reduxjs/toolkit'; + +export const CartSlice = createSlice({ + name: 'cart', + initialState: { + items: [], // Initialize items as an empty array + }, + reducers: { + addItem: (state, action) => { + // action.payload should be a product object + const product = action.payload; + // If the product already exists in cart (by name), increase quantity, else push new + const existingIndex = state.items.findIndex(item => item.name === product.name); + if (existingIndex !== -1) { + state.items[existingIndex].quantity = (state.items[existingIndex].quantity || 1) + 1; + } else { + state.items.push({ ...product, quantity: 1 }); + } + }, + removeItem: (state, action) => { + const name = action.payload; + state.items = state.items.filter(item => item.name !== name); + }, + updateQuantity: (state, action) => { + const { name, quantity } = action.payload; + const idx = state.items.findIndex(item => item.name === name); + if (idx !== -1) { + state.items[idx].quantity = quantity; + if (quantity <= 0) { + state.items.splice(idx, 1); + } + } + + }, + }, +}); + +export const { addItem, removeItem, updateQuantity } = CartSlice.actions; + +export default CartSlice.reducer; diff --git a/src/CartSlice.jsx b/src/CartSlice.jsx index 32b8761ed0..deb529a9a2 100644 --- a/src/CartSlice.jsx +++ b/src/CartSlice.jsx @@ -1,23 +1,3 @@ -import { createSlice } from '@reduxjs/toolkit'; - -export const CartSlice = createSlice({ - name: 'cart', - initialState: { - items: [], // Initialize items as an empty array - }, - reducers: { - addItem: (state, action) => { - - }, - removeItem: (state, action) => { - }, - updateQuantity: (state, action) => { - - - }, - }, -}); - -export const { addItem, removeItem, updateQuantity } = CartSlice.actions; - -export default CartSlice.reducer; +// Re-export to keep compatibility with existing imports +export { default } from './CartSlice.js'; +export { addItem, removeItem, updateQuantity } from './CartSlice.js'; diff --git a/src/ProductList.jsx b/src/ProductList.jsx index 7682c04fc4..98203e97a7 100644 --- a/src/ProductList.jsx +++ b/src/ProductList.jsx @@ -1,9 +1,11 @@ -import React, { useState, useEffect } from 'react'; +/* eslint-disable react/prop-types */ +import { useState } from 'react'; import './ProductList.css' import CartItem from './CartItem'; +import { useDispatch, useSelector } from 'react-redux'; +import { addItem } from './CartSlice'; function ProductList({ onHomeClick }) { const [showCart, setShowCart] = useState(false); - const [showPlants, setShowPlants] = useState(false); // State to control the visibility of the About Us page const plantsArray = [ { @@ -233,6 +235,19 @@ function ProductList({ onHomeClick }) { textDecoration: 'none', } + const dispatch = useDispatch(); + const cartItems = useSelector(state => state.cart.items); + + // total number of items (sum of quantities) + const calculateTotalQuantity = () => { + return cartItems ? cartItems.reduce((total, item) => total + (item.quantity || 0), 0) : 0; + }; + + const itemsInCartByName = cartItems.reduce((acc, item) => { + acc[item.name] = true; + return acc; + }, {}); + const handleHomeClick = (e) => { e.preventDefault(); onHomeClick(); @@ -244,8 +259,8 @@ function ProductList({ onHomeClick }) { }; 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 + // Show plants view and ensure cart is hidden + setShowCart(false); }; const handleContinueShopping = (e) => { @@ -269,19 +284,58 @@ function ProductList({ onHomeClick }) {
handlePlantsClick(e)} style={styleA}>Plants
-
handleCartClick(e)} style={styleA}>

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

+ + + + + + +

+
+ {calculateTotalQuantity() > 0 && ( + {calculateTotalQuantity()} + )} +
{!showCart ? (
- - + {plantsArray.map((categoryObj) => ( +
+

{categoryObj.category}

+
+ {categoryObj.plants.map((plant) => ( +
+

{plant.name}

+ {plant.name} +

{plant.description}

+

{plant.cost}

+ +
+ ))} +
+
+ ))}
) : ( )} ); + + function handleAddToCart(plant) { + // Dispatch the selected plant to the cart slice + dispatch(addItem(plant)); + } } export default ProductList; From 206e325e3ccf8d425f2240d8055ff44d61e2d485 Mon Sep 17 00:00:00 2001 From: Raulkumar <42264691+Raulkumar@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:17:50 +0530 Subject: [PATCH 2/2] Add CONTRIBUTING, CODE_OF_CONDUCT, simple-interest script and update README --- CODE_OF_CONDUCT.md | 3 +++ CONTRIBUTING.md | 9 +++++++++ README.md | 43 ++++++++++++++++++++++++++++++++++++++++++- simple-interest.sh | 17 +++++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 simple-interest.sh diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..7322a6d698 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Code of Conduct + +Be respectful to others. This project follows a Contributor Covenant-style code of conduct. Harassment, hate speech, or other abusive behavior will not be tolerated. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..6c3ed68b7c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Contributing + +Thanks for your interest in contributing to this project! + +- Fork the repository and create a feature branch +- Make your changes and commit with clear messages +- Open a pull request describing your changes + +Please keep changes focused and add tests where helpful. \ No newline at end of file diff --git a/README.md b/README.md index 5884e26a5b..5132b57831 100644 --- a/README.md +++ b/README.md @@ -1 +1,42 @@ -# coding-project-template \ No newline at end of file +# e-plantShopping + +This repository contains the e-plantShopping demo application (React + Vite) used for learning Redux and basic frontend patterns. + +Contents: +- `src/` - React source files +- `public/` - static assets +- `LICENSE` - Apache 2.0 license + +How to run locally + +1. Install dependencies: + +```powershell +npm install +``` + +2. Start dev server: + +```powershell +npm run dev +``` + +3. Open the app in the browser (typically http://localhost:5173) + +Simple interest script + +There is a helper shell script `simple-interest.sh` which calculates simple interest. + +Usage: + +```powershell +# on Unix/macOS +./simple-interest.sh