diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 66e596d..42a2ead 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -43,6 +43,7 @@
"cmdk": "^1.1.1",
"date-fns": "^3.6.0",
"embla-carousel-react": "^8.6.0",
+ "framer-motion": "^12.23.24",
"input-otp": "^1.4.2",
"lucide-react": "^0.462.0",
"next-themes": "^0.3.0",
@@ -4517,6 +4518,33 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/framer-motion": {
+ "version": "12.23.24",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.24.tgz",
+ "integrity": "sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^12.23.23",
+ "motion-utils": "^12.23.6",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -5170,6 +5198,21 @@
"node": ">= 18"
}
},
+ "node_modules/motion-dom": {
+ "version": "12.23.23",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz",
+ "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-utils": "^12.23.6"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "12.23.6",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz",
+ "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
+ "license": "MIT"
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 9f8ace1..22787d0 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -45,6 +45,7 @@
"cmdk": "^1.1.1",
"date-fns": "^3.6.0",
"embla-carousel-react": "^8.6.0",
+ "framer-motion": "^12.23.24",
"input-otp": "^1.4.2",
"lucide-react": "^0.462.0",
"next-themes": "^0.3.0",
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 416435e..374c8fe 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -9,6 +9,10 @@ import Browse from "./pages/Browse";
import Sell from "./pages/Sell";
import ProductDetailsPage from "./pages/ProductDetail";
import Navbar from "./components/Navbar";
+import { CartProvider } from "./components/CartContext.jsx";
+import Home from "./pages/Home.jsx";
+import Cart from "./pages/Cart.jsx";
+import Payment from "./pages/Payment";
import Dashboard from "./pages/Dashboard";
const queryClient = new QueryClient();
@@ -20,16 +24,22 @@ const App = () => (
-
+
+
} />
+
} />
} />
} />
} />
+ } />
+ } />
+ } />
} />
} />
+
diff --git a/frontend/src/components/CartContext.jsx b/frontend/src/components/CartContext.jsx
new file mode 100644
index 0000000..a1f5945
--- /dev/null
+++ b/frontend/src/components/CartContext.jsx
@@ -0,0 +1,38 @@
+import React, { createContext, useReducer, useEffect, useState } from "react";
+
+export const CartContext = createContext();
+
+const initialState = {
+ cart: JSON.parse(localStorage.getItem("cart")) || [],
+};
+
+const reducer = (state, action) => {
+ switch (action.type) {
+ case "ADD_ITEM":
+ return { ...state, cart: [...state.cart, action.payload] };
+ case "REMOVE_ITEM":
+ return {
+ ...state,
+ cart: state.cart.filter((_, i) => i !== action.payload),
+ };
+ case "CLEAR_CART":
+ return { ...state, cart: [] };
+ default:
+ return state;
+ }
+};
+
+export const CartProvider = ({ children }) => {
+ const [state, dispatch] = useReducer(reducer, initialState);
+ const [notification, setNotification] = useState(null);
+
+ useEffect(() => {
+ localStorage.setItem("cart", JSON.stringify(state.cart));
+ }, [state.cart]);
+
+ return (
+
+ {children}
+
+ );
+};
\ No newline at end of file
diff --git a/frontend/src/pages/Cart.jsx b/frontend/src/pages/Cart.jsx
new file mode 100644
index 0000000..a48c0b2
--- /dev/null
+++ b/frontend/src/pages/Cart.jsx
@@ -0,0 +1,271 @@
+import React, { useContext } from "react";
+import { CartContext } from "../components/CartContext";
+import { Link } from "react-router-dom";
+import { motion, AnimatePresence } from "framer-motion";
+
+const Cart = () => {
+ const { state, dispatch } = useContext(CartContext);
+
+ // Group items by ID and calculate quantities
+ const cartItems = state.cart.reduce((acc, item) => {
+ const existingItem = acc.find(i => i.id === item.id);
+ if (existingItem) {
+ existingItem.quantity += 1;
+ existingItem.totalPrice = existingItem.quantity * existingItem.price;
+ } else {
+ acc.push({ ...item, quantity: 1, totalPrice: item.price });
+ }
+ return acc;
+ }, []);
+
+ const subtotal = cartItems.reduce((sum, item) => sum + item.totalPrice, 0);
+ const shipping = subtotal > 0 ? 99 : 0;
+ const total = subtotal + shipping;
+
+ const updateQuantity = (id, newQuantity) => {
+ if (newQuantity < 1) return;
+
+ // Find all items with this ID
+ const items = state.cart.filter(item => item.id === id);
+
+ if (newQuantity > items.length) {
+ // Add more items
+ const itemToAdd = items[0];
+ dispatch({ type: "ADD_ITEM", payload: itemToAdd });
+ } else if (newQuantity < items.length) {
+ // Remove items
+ const itemsToRemove = items.length - newQuantity;
+ for (let i = 0; i < itemsToRemove; i++) {
+ const lastIndex = state.cart.map((item, index) => ({ item, index }))
+ .filter(({ item }) => item.id === id)
+ .pop().index;
+ dispatch({ type: "REMOVE_ITEM", payload: lastIndex });
+ }
+ }
+ };
+
+ const removeItemCompletely = (id) => {
+ const itemsToRemove = state.cart
+ .map((item, index) => ({ item, index }))
+ .filter(({ item }) => item.id === id)
+ .map(({ index }) => index)
+ .reverse(); // Remove from end to avoid index issues
+
+ itemsToRemove.forEach(index => {
+ dispatch({ type: "REMOVE_ITEM", payload: index });
+ });
+ };
+
+ const clearCart = () => {
+ dispatch({ type: "CLEAR_CART" });
+ };
+
+ return (
+
+ {/* Header */}
+
+
+ Your Shopping Cart
+
+
+ {cartItems.length === 0 ? "Your cart is waiting to be filled! 🛍️" : `You have ${cartItems.length} unique item${cartItems.length > 1 ? 's' : ''} in your cart`}
+
+
+
+
+ {/* Cart Items */}
+
+ {cartItems.length === 0 ? (
+
+ 🛒
+
+ Your cart is empty
+
+
+ Discover amazing products and add them to your cart!
+
+
+ Start Shopping
+
+
+ ) : (
+ <>
+ {/* Cart Header */}
+
+
+ Cart Items ({state.cart.length})
+
+
+ 🗑️
+ Clear Cart
+
+
+
+ {/* Cart Items List */}
+
+
+ {cartItems.map((item, index) => (
+
+
+ {/* Product Image */}
+
+
+
+
+ {/* Product Info */}
+
+
+ {item.name}
+
+
+ ₹{item.price.toLocaleString()} each
+
+
+ {/* Quantity Controls */}
+
+ updateQuantity(item.id, item.quantity - 1)}
+ className="w-8 h-8 flex items-center justify-center rounded-full hover:bg-gray-200 transition-colors duration-200 text-lg font-bold"
+ disabled={item.quantity <= 1}
+ >
+ −
+
+
+ {item.quantity}
+
+ updateQuantity(item.id, item.quantity + 1)}
+ className="w-8 h-8 flex items-center justify-center rounded-full hover:bg-gray-200 transition-colors duration-200 text-lg font-bold"
+ >
+ +
+
+
+
+ {/* Total Price for this item */}
+
+ ₹{(item.totalPrice).toLocaleString()}
+
+
+
+
+ {/* Remove Button */}
+
removeItemCompletely(item.id)}
+ className="flex-shrink-0 w-12 h-12 flex items-center justify-center bg-red-50 text-red-500 rounded-xl hover:bg-red-100 transition-all duration-200 transform hover:scale-110"
+ title="Remove all"
+ >
+ 🗑️
+
+
+
+ ))}
+
+
+ >
+ )}
+
+
+ {/* Order Summary - Only show when cart has items */}
+ {cartItems.length > 0 && (
+
+
+
+ Order Summary
+
+
+ {/* Price Breakdown */}
+
+
+ Subtotal ({state.cart.length} items)
+ ₹{subtotal.toLocaleString()}
+
+
+ Shipping
+ {shipping > 0 ? `₹${shipping}` : "Free"}
+
+ {shipping > 0 && subtotal < 999 && (
+
+ 🚚 Add ₹{(999 - subtotal).toLocaleString()} more for free shipping!
+
+ )}
+
+
+ Total
+
+ ₹{total.toLocaleString()}
+
+
+
+
+
+ {/* Action Buttons */}
+
+
+ Proceed to Payment
+
+
+ Continue Shopping
+
+
+
+ {/* Security Badge */}
+
+
+ 🔒
+ Secure Checkout
+
+
+ Your payment information is encrypted and secure
+
+
+
+
+ )}
+
+
+ {/* Background Decoration */}
+
+
+ );
+};
+
+export default Cart;
\ No newline at end of file
diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx
new file mode 100644
index 0000000..b62ca17
--- /dev/null
+++ b/frontend/src/pages/Home.jsx
@@ -0,0 +1,187 @@
+import React, { useContext } from "react";
+import { CartContext } from "../components/CartContext";
+import { Link } from "react-router-dom";
+import { motion, AnimatePresence } from "framer-motion";
+
+const products = [
+ {
+ id: 1,
+ name: "Wireless Headphones",
+ price: 2999,
+ image: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
+ description: "Premium sound quality with noise cancellation"
+ },
+ {
+ id: 2,
+ name: "Smartwatch",
+ price: 1999,
+ image: "https://images.unsplash.com/photo-1523275335684-37898b6baf30?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
+ description: "Track your fitness and stay connected"
+ },
+ {
+ id: 3,
+ name: "Bluetooth Speaker",
+ price: 1499,
+ image: "https://images.unsplash.com/photo-1608043152269-423dbba4e7e1?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
+ description: "Portable speaker with crystal clear audio"
+ },
+ {
+ id: 4,
+ name: "Gaming Mouse",
+ price: 1299,
+ image: "https://images.unsplash.com/photo-1527864550417-7fd91fc51a46?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
+ description: "High precision gaming mouse with RGB lighting"
+ },
+ {
+ id: 5,
+ name: "Laptop Stand",
+ price: 899,
+ image: "https://images.unsplash.com/photo-1586953208448-b95a79798f07?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
+ description: "Ergonomic aluminum laptop stand"
+ },
+ {
+ id: 6,
+ name: "Wireless Keyboard",
+ price: 1799,
+ image: "https://images.unsplash.com/photo-1587829741301-dc798b83add3?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80",
+ description: "Mechanical wireless keyboard"
+ }
+];
+
+const Home = () => {
+ const { dispatch, setNotification, notification } = useContext(CartContext);
+
+ const addToCart = (product) => {
+ dispatch({ type: "ADD_ITEM", payload: product });
+ setNotification(product);
+ setTimeout(() => setNotification(null), 2000);
+ };
+
+ return (
+
+ {/* Header */}
+
+
+ Discover Amazing Products
+
+
+ Explore our curated collection of premium electronics and accessories
+
+
+
+ {/* Products Grid */}
+
+
+ {products.map((product, index) => (
+
+ {/* Product Image - Fixed with proper height */}
+
+
+
+
+
+ {/* Product Info */}
+
+
+
+ {product.name}
+
+
+ ₹{product.price.toLocaleString()}
+
+
+
+
+ {product.description}
+
+
+
addToCart(product)}
+ className="w-full bg-gradient-to-r from-blue-600 to-purple-600 text-white py-3 px-6 rounded-xl font-semibold hover:from-blue-700 hover:to-purple-700 transition-all duration-300 transform hover:scale-105 active:scale-95 shadow-lg hover:shadow-xl mt-auto"
+ whileHover={{ scale: 1.02 }}
+ whileTap={{ scale: 0.98 }}
+ >
+ Add to Cart 🛒
+
+
+
+ ))}
+
+
+
+ {/* Floating Cart Button */}
+
+
+ View Cart
+ 🛒
+
+
+
+ {/* Notification */}
+
+ {notification && (
+
+
+
+
+
+
+ {notification.name}
+
+
+ Added to cart successfully! 🎉
+
+
+
+ )}
+
+
+ {/* Background Decoration */}
+
+
+ );
+};
+
+export default Home;
\ No newline at end of file
diff --git a/frontend/src/pages/Payment.jsx b/frontend/src/pages/Payment.jsx
new file mode 100644
index 0000000..9e02637
--- /dev/null
+++ b/frontend/src/pages/Payment.jsx
@@ -0,0 +1,496 @@
+import React, { useState, useContext } from "react";
+import { CartContext } from "../components/CartContext";
+import { Link, useNavigate } from "react-router-dom";
+import { motion, AnimatePresence } from "framer-motion";
+
+const Payment = () => {
+ const { state, dispatch } = useContext(CartContext);
+ const navigate = useNavigate();
+ const [paymentMethod, setPaymentMethod] = useState("card");
+ const [formData, setFormData] = useState({
+ cardNumber: "",
+ cardName: "",
+ expiry: "",
+ cvv: "",
+ upiId: "",
+ wallet: "",
+ bank: ""
+ });
+ const [isProcessing, setIsProcessing] = useState(false);
+
+ const total = state.cart.reduce((sum, item) => sum + item.price, 0);
+ const tax = total * 0.18;
+ const shipping = 99;
+ const finalTotal = total + tax + shipping;
+
+ const handleInputChange = (e) => {
+ const { name, value } = e.target;
+
+ // Format card number with spaces
+ if (name === "cardNumber") {
+ const formattedValue = value.replace(/\s/g, '').replace(/(\d{4})/g, '$1 ').trim();
+ setFormData(prev => ({ ...prev, [name]: formattedValue }));
+ return;
+ }
+
+ // Format expiry date
+ if (name === "expiry") {
+ const formattedValue = value.replace(/\D/g, '').replace(/(\d{2})(\d)/, '$1/$2');
+ setFormData(prev => ({ ...prev, [name]: formattedValue }));
+ return;
+ }
+
+ setFormData(prev => ({ ...prev, [name]: value }));
+ };
+
+ const handlePayment = async (e) => {
+ e.preventDefault();
+ setIsProcessing(true);
+
+ // Simulate payment processing
+ setTimeout(() => {
+ setIsProcessing(false);
+ dispatch({ type: "CLEAR_CART" });
+ navigate("/success");
+ }, 3000);
+ };
+
+ const paymentMethods = [
+ { id: "card", name: "Credit/Debit Card", icon: "💳", color: "from-blue-500 to-blue-700" },
+ { id: "upi", name: "UPI Payment", icon: "📱", color: "from-green-500 to-green-700" },
+ { id: "wallet", name: "Wallet", icon: "👛", color: "from-purple-500 to-purple-700" },
+ { id: "netbanking", name: "Net Banking", icon: "🏦", color: "from-orange-500 to-orange-700" },
+ ];
+
+ const wallets = [
+ { id: "paytm", name: "Paytm", icon: "📲" },
+ { id: "phonepe", name: "PhonePe", icon: "📳" },
+ { id: "amazonpay", name: "Amazon Pay", icon: "🛒" },
+ { id: "other", name: "Other Wallets", icon: "💰" },
+ ];
+
+ const banks = [
+ { id: "sbi", name: "State Bank of India" },
+ { id: "hdfc", name: "HDFC Bank" },
+ { id: "icici", name: "ICICI Bank" },
+ { id: "axis", name: "Axis Bank" },
+ { id: "kotak", name: "Kotak Mahindra Bank" },
+ { id: "other", name: "Other Banks" },
+ ];
+
+ return (
+
+
+ {/* Header */}
+
+
+ Secure Checkout
+
+
+ Complete your purchase with secure payment
+
+
+
+
+ {/* Payment Methods & Form */}
+
+ {/* Payment Method Selection */}
+
+
+
+ Select Payment Method
+
+
+ {paymentMethods.map((method) => (
+
setPaymentMethod(method.id)}
+ className={`p-4 rounded-xl border-2 transition-all duration-200 ${
+ paymentMethod === method.id
+ ? `border-blue-500 bg-gradient-to-r ${method.color} text-white shadow-lg`
+ : "border-gray-200 hover:border-gray-300 bg-white text-gray-700"
+ }`}
+ whileHover={{ scale: 1.02 }}
+ whileTap={{ scale: 0.98 }}
+ >
+
+ {method.icon}
+ {method.name}
+
+
+ ))}
+
+
+
+
+ {/* Payment Form */}
+
+
+
+ {paymentMethod === "card" && "Card Details"}
+ {paymentMethod === "upi" && "UPI Payment"}
+ {paymentMethod === "wallet" && "Digital Wallet"}
+ {paymentMethod === "netbanking" && "Net Banking"}
+
+
+
+
+
+
+
+ {/* Order Summary */}
+
+
+
+ Order Summary
+
+
+ {/* Items List */}
+
+ {state.cart.map((item, index) => (
+
+
+
+
+ {item.name}
+
+
₹{item.price.toLocaleString()}
+
+
+ ))}
+
+
+ {/* Price Breakdown */}
+
+
+ Subtotal ({state.cart.length} items)
+ ₹{total.toLocaleString()}
+
+
+ Shipping
+ ₹{shipping}
+
+
+ Tax (18%)
+ ₹{tax.toLocaleString()}
+
+
+
+ Total Amount
+
+ ₹{finalTotal.toLocaleString()}
+
+
+
+
+
+ {/* Back to Cart */}
+
+ ← Back to Cart
+
+
+
+
+
+ {/* Security Badges */}
+
+ {[
+ { icon: "🔒", text: "256-bit SSL Secure" },
+ { icon: "🛡️", text: "PCI DSS Compliant" },
+ { icon: "💰", text: "100% Money Back" },
+ { icon: "⚡", text: "Instant Refund" }
+ ].map((badge, index) => (
+
+ {badge.icon}
+ {badge.text}
+
+ ))}
+
+
+
+ {/* Background Decoration */}
+
+
+ );
+};
+
+export default Payment;
\ No newline at end of file