{id:"1",name:"Hand Worked Georgette Kurti",category:"Fashion & Apparel",subcategory:"Women",price:1499,originalPrice:2499,image:"https://images.unsplash.com/photo-1610030469983-98e550d6193c?w=600&h=800&fit=crop",rating:4.8,reviews:34,onSale:true}, {id:"2",name:"Exclusive Festival Kurta with Pyjama Set",category:"Fashion & Apparel",subcategory:"Men",price:2199,originalPrice:3499,image:"https://images.unsplash.com/photo-1597983073493-88cd35cf93b0?w=600&h=800&fit=crop",rating:4.9,reviews:52,onSale:true}, {id:"3",name:"Kubera Pattu Soft Silk Saree",category:"Fashion & Apparel",subcategory:"Women",price:4599,originalPrice:6999,image:"https://images.unsplash.com/photo-1617627143750-d86bc21e42bb?w=600&h=800&fit=crop",rating:4.9,reviews:27,onSale:true}, {id:"4",name:"Neon Eclipse Street Set",category:"Fashion & Apparel",subcategory:"Women",price:1899,originalPrice:2799,image:"https://images.unsplash.com/photo-1559551409-dad5b0e1a94f?w=600&h=800&fit=crop",rating:4.7,reviews:18,onSale:true}, {id:"5",name:"Trendy Embroidered Cotton Co-ord Set",category:"Fashion & Apparel",subcategory:"Women",price:1699,originalPrice:null,image:"https://images.unsplash.com/photo-1591369822096-ffd140ec948f?w=600&h=800&fit=crop",rating:4.6,reviews:41,onSale:false}, {id:"6",name:"Premium Imported Backpack",category:"Accessories",subcategory:"Bags",price:1030,originalPrice:1599,image:"https://images.unsplash.com/photo-1553062407-98eeb64c6a62?w=600&h=800&fit=crop",rating:4.5,reviews:63,onSale:true}, {id:"7",name:"Elegance Glow Stone Bangles",category:"Accessories",subcategory:"Jewellery",price:850,originalPrice:1299,image:"https://images.unsplash.com/photo-1602173574767-37ac01994b2a?w=600&h=800&fit=crop",rating:4.7,reviews:89,onSale:true}, {id:"8",name:"Python Tote Cum Sling Bag",category:"Accessories",subcategory:"Bags",price:880,originalPrice:1499,image:"https://images.unsplash.com/photo-1591561954557-26941169b49e?w=600&h=800&fit=crop",rating:4.6,reviews:45,onSale:true}, {id:"9",name:"Jumbo Premium Cotton Bedsheet Set",category:"Home Essentials",subcategory:"Linen",price:1090,originalPrice:1799,image:"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=600&h=800&fit=crop",rating:4.8,reviews:112,onSale:true}, {id:"10",name:"Premium Cotton Kitchen Towel Set",category:"Home Essentials",subcategory:"Linen",price:449,originalPrice:null,image:"https://images.unsplash.com/photo-1604335399105-a0c585fd81a1?w=600&h=800&fit=crop",rating:4.4,reviews:28,onSale:false}, {id:"11",name:"Mindful Tee – Oversized Streetwear",category:"Fashion & Apparel",subcategory:"Men",price:899,originalPrice:null,image:"https://images.unsplash.com/photo-1521572163474-6864f9cf17ab?w=600&h=800&fit=crop",rating:4.9,reviews:76,onSale:false}, {id:"12",name:"Famous Tee – Statement Oversized Fit",category:"Fashion & Apparel",subcategory:"Men",price:899,originalPrice:1299,image:"https://images.unsplash.com/photo-1583743814966-8936f5b7be1a?w=600&h=800&fit=crop",rating:4.7,reviews:44,onSale:true}, {id:"13",name:"Brass Pooja Thali Set",category:"Home Essentials",subcategory:"Utensils",price:1299,originalPrice:null,image:"https://images.unsplash.com/photo-1609766856920-7f0c7b0f2e0c?w=600&h=800&fit=crop",rating:4.9,reviews:23,onSale:false}, {id:"14",name:"The King – Premium Coffee Mug",category:"Stationery",subcategory:"Mugs",price:499,originalPrice:null,image:"https://images.unsplash.com/photo-1514228742587-6b1558fcca3d?w=600&h=800&fit=crop",rating:4.8,reviews:156,onSale:false}, {id:"15",name:"Handcrafted Leather Journal",category:"Stationery",subcategory:"Notebooks",price:649,originalPrice:null,image:"https://images.unsplash.com/photo-1544816155-12df9643f363?w=600&h=800&fit=crop",rating:4.6,reviews:67,onSale:false}, {id:"16",name:"Hand Bag – Double Partition Elegance",category:"Accessories",subcategory:"Bags",price:830,originalPrice:1399,image:"https://images.unsplash.com/photo-1584917865442-de89df76afd3?w=600&h=800&fit=crop",rating:4.5,reviews:38,onSale:true}, ]; const CATEGORIES = [ {name:"Fashion & Apparel",slug:"fashion",subcategories:["Men","Women","Kids"]}, {name:"Accessories",slug:"accessories",subcategories:["Bags","Jewellery","Footwear"]}, {name:"Home Essentials",slug:"home",subcategories:["Linen","Utensils"]}, {name:"Stationery",slug:"stationery",subcategories:["Mugs","Notebooks"]}, ]; const CAT_HIGHLIGHTS = [ {label:"MEN",img:"https://images.unsplash.com/photo-1597983073493-88cd35cf93b0?w=300&h=300&fit=crop",count:PRODUCTS.filter(p=>p.subcategory==="Men").length}, {label:"WOMEN",img:"https://images.unsplash.com/photo-1610030469983-98e550d6193c?w=300&h=300&fit=crop",count:PRODUCTS.filter(p=>p.subcategory==="Women").length}, {label:"ACCESSORIES",img:"https://images.unsplash.com/photo-1584917865442-de89df76afd3?w=300&h=300&fit=crop",count:PRODUCTS.filter(p=>p.category==="Accessories").length}, {label:"HOME",img:"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=300&h=300&fit=crop",count:PRODUCTS.filter(p=>p.category==="Home Essentials").length}, ]; const { useState, useEffect, useCallback, useRef } = React; const fmt = n => "₹" + n.toLocaleString("en-IN"); // ── Sub-components ── function Toast({ toasts }) { return (
{toasts.map(t=>(
Added {t.name} to cart
))}
); } // ── Auth helpers (Supabase) ── function LoginModal({ isOpen, onClose, onLogin }) { const [tab, setTab] = useState("login"); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [name, setName] = useState(""); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); useEffect(()=>{if(!isOpen){setEmail("");setPassword("");setName("");setError("");setLoading(false)}},[isOpen]); const handleGoogle = async () => { setError(""); setLoading(true); try { const provider = new firebase.auth.GoogleAuthProvider(); const result = await fbAuth.signInWithPopup(provider); await exchangeFirebaseToken(result.user); const { data: { session } } = await sb.auth.getSession(); onLogin(session.user); onClose(); } catch (err) { setError(err.message || "Google sign-in failed."); setLoading(false); } }; const handleSubmit = async (e) => { e.preventDefault(); setError(""); if (!email || !password || (tab==="signup"&&!name)) { setError("All fields are required."); return; } if (password.length < 6) { setError("Password must be at least 6 characters."); return; } setLoading(true); try { if (tab === "signup") { const result = await fbAuth.createUserWithEmailAndPassword(email, password); await result.user.updateProfile({ displayName: name || email.split("@")[0] }); await exchangeFirebaseToken(result.user); const { data: { session } } = await sb.auth.getSession(); onLogin(session.user); onClose(); } else { const result = await fbAuth.signInWithEmailAndPassword(email, password); await exchangeFirebaseToken(result.user); const { data: { session } } = await sb.auth.getSession(); onLogin(session.user); onClose(); } } catch (err) { if (err.code === "auth/user-not-found" || err.code === "auth/wrong-password") { setError("Invalid email or password."); } else if (err.code === "auth/email-already-in-use") { setError("An account with this email already exists."); } else { setError(err.message || "Something went wrong."); } } finally { setLoading(false); } }; return (
e.stopPropagation()}>
{error &&
{error}
}
{tab==="signup" && (
setName(e.target.value)} placeholder="Your name" autoComplete="name"/>
)}
setEmail(e.target.value)} placeholder="you@example.com" autoComplete="email"/>
setPassword(e.target.value)} placeholder="••••••••" autoComplete={tab==="signup"?"new-password":"current-password"}/>
or
{tab==="login"?( <>Don’t have an account? ):( <>Already have an account? )}
); } function Navbar({ cartCount, onCartClick, user, onLoginClick, onLogout, onNavigate, currentView, products }) { const [scrolled, setScrolled] = useState(false); const [mobileOpen, setMobileOpen] = useState(false); const [searchOpen, setSearchOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(""); const [openMenu, setOpenMenu] = useState(null); const [userMenuOpen, setUserMenuOpen] = useState(false); const searchRef = useRef(null); const userMenuRef = useRef(null); const menuTimer = useRef(null); useEffect(()=>{const h=()=>setScrolled(window.scrollY>10);window.addEventListener("scroll",h,{passive:true});return ()=>window.removeEventListener("scroll",h)},[]); useEffect(()=>{const h=e=>{if(userMenuRef.current&&!userMenuRef.current.contains(e.target))setUserMenuOpen(false)};document.addEventListener("mousedown",h);return ()=>document.removeEventListener("mousedown",h)},[]); useEffect(()=>{if(searchOpen){document.body.classList.add("no-scroll");setTimeout(()=>searchRef.current?.focus(),100)}else{document.body.classList.remove("no-scroll");setSearchQuery("")}},[searchOpen]); useEffect(()=>{const h=e=>{if(e.key==="Escape")setSearchOpen(false);if((e.ctrlKey||e.metaKey)&&e.key==="k"){e.preventDefault();setSearchOpen(true)}};document.addEventListener("keydown",h);return ()=>document.removeEventListener("keydown",h)},[]); const displayName = user ? (user.user_metadata?.full_name || user.email) : ""; const initials = user ? displayName.split(" ").map(n=>n[0]).join("").toUpperCase().slice(0,2) : ""; const searchResults = searchQuery ? products.filter(p=>p.name.toLowerCase().includes(searchQuery.toLowerCase())) : []; const menuIcons = { "Fashion & Apparel": "fa-solid fa-shirt", "Accessories": "fa-solid fa-gem", "Home Essentials": "fa-solid fa-house", "Stationery": "fa-solid fa-pen", }; return ( <> {/* Mobile */}
{/* Mobile Sheet Overlay */}
setMobileOpen(false)}>
basketful
{e.preventDefault();setMobileOpen(false);onNavigate('home')}} style={{display:"block",marginBottom:4,fontSize:15,padding:"12px 16px"}}>Home {e.preventDefault();setMobileOpen(false);onNavigate('shop')}} style={{display:"block",marginBottom:4,fontSize:15,padding:"12px 16px"}}>All Products {CATEGORIES.map(cat=>(
{cat.name}
{cat.subcategories.map(sub=>( {e.preventDefault();setMobileOpen(false);onNavigate('shop',{category:cat.slug,subcategory:sub})}} style={{display:"block",padding:"10px 16px",fontSize:13,color:"var(--text-muted)",textDecoration:"none",borderRadius:8}} onMouseEnter={e=>{e.currentTarget.style.background="rgba(0,71,65,.03)";e.currentTarget.style.color="var(--brand)"}} onMouseLeave={e=>{e.currentTarget.style.background="transparent";e.currentTarget.style.color="var(--text-muted)"}} >{sub} ))} {e.preventDefault();setMobileOpen(false);onNavigate('shop',{category:cat.slug})}} style={{display:"block",padding:"10px 16px",fontSize:13,fontWeight:700,color:"var(--brand)",textDecoration:"none",borderRadius:8}} >All {cat.name} →
))}
{user ? ( <> {e.preventDefault();setMobileOpen(false);onNavigate('orders')}} style={{display:"block",padding:"12px 16px",fontSize:14,fontWeight:600,color:"var(--text-muted)",textDecoration:"none",borderRadius:10}} >My Orders ) : ( )}
{/* Search Overlay */}
setSearchOpen(false)}>
e.stopPropagation()}>
setSearchQuery(e.target.value)} style={{flex:1,border:"none",outline:"none",fontSize:15,color:"var(--brand)",background:"transparent",fontFamily:"inherit"}} />
{!searchQuery ? (

Type to search {products.length} products

) : searchResults.length===0 ? (

No products found for "{searchQuery}"

) : searchResults.map(p=>(
{setSearchOpen(false);onNavigate('product',{productId:p.id})}} style={{display:"flex",alignItems:"center",gap:12,padding:"10px 12px",borderRadius:10,cursor:"pointer",transition:"background .15s"}} onMouseEnter={e=>e.currentTarget.style.background="rgba(0,71,65,.03)"} onMouseLeave={e=>e.currentTarget.style.background="transparent"} >
{p.name}

{p.name}

{p.subcategory} · {fmt(p.price)}

))}
); } function Hero({ onExplore, onNavigate }) { return (

New Collection · 2026

Style that tells
your story.

Handcrafted fashion, accessories, home essentials, and stationery — sourced with intention from responsible suppliers across India.

Featured
Accessories
); } function CategoryHighlights({ onNavigate, products }) { const navMap = { MEN: { category: 'fashion', subcategory: 'Men' }, WOMEN: { category: 'fashion', subcategory: 'Women' }, ACCESSORIES: { category: 'accessories' }, HOME: { category: 'home' }, }; const catHighlights = [ {label:"MEN",img:"https://images.unsplash.com/photo-1597983073493-88cd35cf93b0?w=300&h=300&fit=crop",count:products.filter(p=>p.subcategory==="Men").length}, {label:"WOMEN",img:"https://images.unsplash.com/photo-1610030469983-98e550d6193c?w=300&h=300&fit=crop",count:products.filter(p=>p.subcategory==="Women").length}, {label:"ACCESSORIES",img:"https://images.unsplash.com/photo-1584917865442-de89df76afd3?w=300&h=300&fit=crop",count:products.filter(p=>p.category==="Accessories").length}, {label:"HOME",img:"https://images.unsplash.com/photo-1631049307264-da0ec9d70304?w=300&h=300&fit=crop",count:products.filter(p=>p.category==="Home Essentials").length}, ]; return (

Shop by Category

Explore Collections

{catHighlights.map(c=>( {e.preventDefault();onNavigate('shop',navMap[c.label]||{})}}>
{c.label}/
{c.label}
{c.count} Items
))}
); } function ProductCard({ product, onAdd, onClick, onWishlist, isWishlisted }) { const [loaded, setLoaded] = useState(false); const [added, setAdded] = useState(false); const inStock = product.inStock !== false; const stockCount = product.stock_count; const lowStock = stockCount !== undefined && stockCount <= 5 && stockCount > 0; const handleAdd = (e) => { e.stopPropagation(); onAdd(product); setAdded(true); setTimeout(()=>setAdded(false),1800); }; return (
{product.onSale && SALE} {onWishlist && ( )} {!inStock &&
Sold Out
} {product.name}setLoaded(true)} loading="lazy"/>

{product.subcategory}

{product.name}

{"★".repeat(Math.floor(product.rating))}{"☆".repeat(5-Math.floor(product.rating))} {" "}({product.reviews})
{fmt(product.price)} {product.originalPrice && {fmt(product.originalPrice)}}
{lowStock &&

Only {stockCount} left

} {!lowStock && inStock && stockCount > 0 &&

In Stock

}
); } function ProductSection({ products, title, subtitle, link, onAdd, altBg, onProductClick, onViewAll, onWishlist, wishlist }) { return (

{subtitle}

{title}

{link && {e.preventDefault();onViewAll&&onViewAll()}}>{link}}
{products.map(p=>onProductClick(p.id):undefined} onWishlist={onWishlist} isWishlisted={wishlist?.has(p.id)}/>)}
); } function SaleBanner({ onExplore, onShopSale }) { return (
Limited Time

End of Season Sale

Up to 50% off on selected items

); } function Philosophy() { return (

Our Philosophy

“Basketful began with a simple goal: to make shopping cleaner, simpler, and more honest. We cut the clutter — no over styling, no waste — just trusted products from responsible suppliers.”
— Basketful, Kochi
); } function Footer() { return ( ); } function CartSidebar({ cart, isOpen, onClose, onUpdateQty, onRemove, onCheckout, onSaveForLater }) { const subtotal = cart.reduce((s,i)=>s+i.price*i.qty,0); const shipping = 0; return ( <>

Your Cart

{cart.length===0?(

Your cart is empty

):cart.map(item=>(
{item.name}/
{item.name}
{fmt(item.price)}
{item.qty}
))}
{cart.length>0 && (
Subtotal{fmt(subtotal)}
{shipping===0?"Free shipping":`Shipping: ${fmt(shipping)}`}
Free Shipping
)}
); } function CheckoutModal({ isOpen, cart, onClose, user }) { const [step, setStep] = useState("form"); const [form, setForm] = useState({firstName:"",lastName:"",email:"",phone:"",address:"",city:"",state:"",pin:""}); const [error, setError] = useState(""); const [orderId, setOrderId] = useState(null); const subtotal = cart.reduce((s,i)=>s+i.price*i.qty,0); const shipping = 0; const total = subtotal+shipping; useEffect(()=>{if(!isOpen){setForm({firstName:"",lastName:"",email:"",phone:"",address:"",city:"",state:"",pin:""});setStep("form");setError("");setOrderId(null)}},[isOpen]); const update = e => setForm(prev=>({...prev,[e.target.name]:e.target.value})); const canSubmit = form.firstName&&form.lastName&&form.email&&form.phone&&form.address&&form.city&&form.state&&form.pin; const handlePlaceOrder = async (e) => { e.preventDefault(); if(!canSubmit)return; if(!user){setError("Please sign in to place an order.");return;} setError(""); try { const {data:order,error:orderErr}=await sb.from("orders").insert({ user_id:user.id,status:"confirmed",subtotal,shipping,total, shipping_name:`${form.firstName} ${form.lastName}`, shipping_address:form.address,shipping_city:form.city, shipping_state:form.state,shipping_pin:form.pin, shipping_phone:form.phone }).select().single(); if(orderErr)throw orderErr; const items=cart.map(p=>({order_id:order.id,product_id:p.id,product_name:p.name,product_image:p.image,price:p.price,quantity:p.qty})); const {error:itemsErr}=await sb.from("order_items").insert(items); if(itemsErr)throw itemsErr; setOrderId(order.id); setStep("done"); } catch(err){setError(err.message||"Order failed. Try again.")} }; return (
e.stopPropagation()}> {step==="done"?(

Order Confirmed

Thank you, {form.firstName}. Your order of {fmt(total)} has been placed.

We'll send a confirmation to {form.email}.

{orderId&&

Order ID: {orderId.slice(0,8)}

}
):( <>

Checkout

{cart.length} {cart.length===1?"item":"items"} · {fmt(total)}

{error &&
{error}
}

Shipping Address

Payment

Cash on Delivery
UPI / Net Banking
Subtotal{fmt(subtotal)}
Shipping{shipping===0?"Free":fmt(shipping)}
Total{fmt(total)}
)}
); } // ── Checkout Page ── function CheckoutPage({ cart, onBack, onDone, user }) { const [form, setForm] = useState(()=>{ try{const saved=localStorage.getItem("basketful_address");if(saved)return JSON.parse(saved)}catch(e){} return {firstName:"",lastName:"",email:"",phone:"",address:"",city:"",state:"",pin:""}; }); const [saveAddress, setSaveAddress] = useState(true); const [error, setError] = useState(""); const [orderId, setOrderId] = useState(null); const [done, setDone] = useState(false); const [placing, setPlacing] = useState(false); const subtotal = cart.reduce((s,i)=>s+i.price*i.qty,0); const savedAmount = cart.reduce((s,i)=>i.originalPrice? (i.originalPrice-i.price)*i.qty+s : s,0); const [couponCode, setCouponCode] = useState(""); const [appliedCoupon, setAppliedCoupon] = useState(null); const [couponError, setCouponError] = useState(""); const [paymentMethod, setPaymentMethod] = useState("cod"); const couponDiscount = appliedCoupon ? (appliedCoupon.discount_percent ? Math.round(subtotal * appliedCoupon.discount_percent / 100) : (appliedCoupon.discount_amount || 0)) : 0; const orderTotal = subtotal - couponDiscount; const shipping = 0; const total = orderTotal + shipping; const update = e => setForm(prev=>({...prev,[e.target.name]:e.target.value})); const canSubmit = form.firstName&&form.lastName&&form.email&&form.phone&&form.address&&form.city&&form.state&&form.pin; const applyCoupon = async () => { if(!couponCode.trim())return; setCouponError("");setAppliedCoupon(null); const {data,error:couponErr}=await sb.from("promo_codes").select("*").eq("code",couponCode.trim().toUpperCase()).eq("active",true).single(); if(couponErr||!data){setCouponError("Invalid code");return;} if(data.min_order && subtotal < data.min_order){setCouponError(`Min order ₹${data.min_order}`);return;} if(data.max_uses && data.current_uses >= data.max_uses){setCouponError("Code expired");return;} if(data.expires_at && new Date(data.expires_at) < new Date()){setCouponError("Code expired");return;} setAppliedCoupon(data);setCouponError(""); }; const placeSupabaseOrder = async (razorpayPaymentId) => { setError("");setPlacing(true); try { const orderPayload = { user_id:user.id,status:"confirmed",subtotal,shipping,total, coupon_code:appliedCoupon?.code||null,discount_amount:couponDiscount, payment_method:paymentMethod, shipping_name:`${form.firstName} ${form.lastName}`, shipping_address:form.address,shipping_city:form.city, shipping_state:form.state,shipping_pin:form.pin, shipping_phone:form.phone }; if(razorpayPaymentId) orderPayload.razorpay_payment_id = razorpayPaymentId; const {data:order,error:orderErr}=await sb.from("orders").insert(orderPayload).select().single(); if(orderErr)throw orderErr; if(saveAddress) localStorage.setItem("basketful_address",JSON.stringify(form)); const productIds = cart.map(p=>p.id); const {data:sellers} = await sb.from("products").select("id,seller_id").in("id",productIds); const sellerMap = {}; if(sellers) sellers.forEach(s=>{sellerMap[s.id]=s.seller_id}); const items = cart.map(p=>({order_id:order.id,product_id:p.id,product_name:p.name,product_image:p.image,price:p.price,quantity:p.qty,seller_id:sellerMap[p.id]||null})); await sb.from("order_items").insert(items); for (const p of cart) { if (sellerMap[p.id]) { const { data: prod } = await sb.from("products").select("stock_count").eq("id", p.id).single(); if (prod && prod.stock_count > 0) await sb.from("products").update({ stock_count: Math.max(0, prod.stock_count - p.qty), in_stock: prod.stock_count - p.qty > 0 }).eq("id", p.id); } } if (appliedCoupon) await sb.from("promo_codes").update({ current_uses: (appliedCoupon.current_uses||0) + 1 }).eq("id", appliedCoupon.id); setOrderId(order.id);setDone(true);onDone(); } catch(err){setError(err.message||"Order failed. Try again.")} setPlacing(false); }; const handlePlaceOrder = async (e) => { e.preventDefault(); if(!canSubmit)return; if(!user){setError("Please sign in to place an order.");return;} if(paymentMethod === "online") { if(!window.Razorpay){ setError("Razorpay not loaded. Refresh and try again."); return; } setPlacing(true); const options = { key: "rzp_test_T3c33zrVbKzQiL", amount: total * 100, currency: "INR", name: "Basketful", description: `${cart.length} item${cart.length!==1?'s':''}`, prefill: { name: `${form.firstName} ${form.lastName}`, email: form.email, contact: form.phone }, handler: async (response) => { try { await placeSupabaseOrder(response.razorpay_payment_id); } catch(e) { setError("Order save failed: " + (e.message || "Unknown error")); setPlacing(false); } }, modal: { ondismiss: () => setPlacing(false) }, theme: { color: "#004741" } }; const rzp = new window.Razorpay(options); rzp.on('payment.failed', (resp) => { setError("Payment failed: "+resp.error.description); setPlacing(false); }); rzp.open(); } else { await placeSupabaseOrder(null); } }; useEffect(()=>{window.scrollTo(0,0)},[]); if(done) return (

Order Confirmed

Thank you, {form.firstName}. Your order of {fmt(total)} has been placed.

We'll send a confirmation to {form.email}.

{orderId&&

Order #{orderId.slice(0,8)}

}
); return (
{e.preventDefault();onBack()}}>← Back to Cart

Secure Checkout

Checkout

{/* Order Items */}

Order Summary

{cart.map(item=>(
{item.name}

{item.name}

{fmt(item.price)} × {item.qty}

{item.originalPrice && (

Saved {fmt((item.originalPrice-item.price)*item.qty)}

)}
{fmt(item.price*item.qty)}
))}
Subtotal{fmt(subtotal)}
{couponDiscount > 0 &&
Coupon ({appliedCoupon.code})-{fmt(couponDiscount)}
}
Shipping{shipping===0?Free:fmt(shipping)}
Total{fmt(total)}
{!appliedCoupon &&
setCouponCode(e.target.value)} placeholder="Promo code" style={{flex:1,padding:"10px 14px",fontSize:13,borderRadius:12}}/>
} {appliedCoupon &&
{appliedCoupon.code} applied
} {couponError &&

{couponError}

}
{error &&
{error}
}

Shipping Address

Payment

setPaymentMethod("cod")} style={{cursor:"pointer"}}>
{paymentMethod==="cod" &&
}
Cash on Delivery
setPaymentMethod("online")} style={{cursor:"pointer"}}>
{paymentMethod==="online" &&
}
Pay Online (UPI / Card / Net Banking)
); } // ── Shop / Category Pages ── function ShopPage({ products, onAdd, onProductClick, category, initialSub, initialSale, onWishlist, wishlist }) { const cat = category ? CATEGORIES.find(c=>c.slug===category||c.name===category) : null; const [activeSub, setActiveSub] = useState(initialSub||""); const [onSale, setOnSale] = useState(initialSale||false); const [search, setSearch] = useState(""); const catProducts = cat ? products.filter(p=>p.category===cat.name) : products; const filtered = catProducts.filter(p=>{ if(search && !p.name.toLowerCase().includes(search.toLowerCase())) return false; if(onSale && !p.onSale) return false; if(activeSub && p.subcategory !== activeSub) return false; return true; }); const allSubs = cat ? cat.subcategories : [...new Set(products.map(p=>p.subcategory))].sort(); return (
{/* Category Hero */} {cat && (

{catProducts.length} Products

{cat.name}

Browse our curated {cat.name.toLowerCase()} collection — handpicked from trusted suppliers across India.

)}
{!cat && <>

{filtered.length} Products

All Products

} {/* Search */}
setSearch(e.target.value)} placeholder={`Search ${cat?cat.name.toLowerCase():'products'}...`} style={{paddingLeft:44,paddingTop:12,paddingBottom:12,borderRadius:14,fontSize:14}} /> {search && }
{/* Subcategory Filters */}
{(cat||!cat) && } {allSubs.map(sub=>( ))}
{cat && !activeSub && !onSale && !search && (
{allSubs.map(sub=>{ const count = catProducts.filter(p=>p.subcategory===sub).length; return ( {e.preventDefault();setActiveSub(sub)}}>
{sub.charAt(0)}
{sub}
{count} Items
); })}
)} {activeSub &&

Showing "{activeSub}".

} {filtered.length===0?(

No products found.

):(
{filtered.map(p=>onProductClick(p.id)} onWishlist={onWishlist} isWishlisted={wishlist?.has(p.id)}/>)}
)}
); } // ── Product Detail Page ── function ProductPage({ product, onAdd, related, onBack, onWishlist, wishlist }) { const [loaded, setLoaded] = useState(false); const [quantity, setQuantity] = useState(1); const [added, setAdded] = useState(false); const [reviews, setReviews] = useState([]); const [reviewForm, setReviewForm] = useState({rating:5,comment:""}); const [submittingReview, setSubmittingReview] = useState(false); const inStock = product.inStock !== false; const desc = product.description || ''; useEffect(()=>{window.scrollTo(0,0);setLoaded(false);setQuantity(1);setAdded(false);loadReviews()},[product.id]); const loadReviews = async () => { const {data} = await sb.from("reviews").select("*").eq("product_id",product.id).order("created_at",{ascending:false}); if(data) setReviews(data); }; const handleAdd = () => { onAdd(product); for(let i=1;isetAdded(false),2000); }; return (
{e.preventDefault();onBack()}}>← Back to Shop
{product.name}setLoaded(true)}/>
{product.subcategory} {product.onSale && SALE}

{product.name}

{fmt(product.price)} {product.originalPrice && {fmt(product.originalPrice)}} {product.onSale && product.originalPrice && {Math.round((1-product.price/product.originalPrice)*100)}% OFF}
{"★".repeat(Math.floor(product.rating))}{"☆".repeat(5-Math.floor(product.rating))} {product.rating} ({product.reviews} reviews)

{desc||"No description available."}

{product.tags && product.tags.length>0 && (
{product.tags.map(tag=>#{tag})}
)}
{quantity}
Free shipping on orders above ₹999 · Estimated delivery {(()=>{const d=new Date();d.setDate(d.getDate()+4);return d.toLocaleDateString('en-IN',{weekday:'short',month:'short',day:'numeric'})})()}
Easy 7-day returns · No questions asked · Free pickup
{/* Reviews */}

Reviews ({reviews.length})

{reviews.length===0 &&

No reviews yet. Be the first to review this product.

} {reviews.map(r=>(
{"★".repeat(r.rating)}{"☆".repeat(5-r.rating)} {new Date(r.created_at).toLocaleDateString('en-IN')}
{r.comment &&

{r.comment}

}
))}

Write a Review

{[1,2,3,4,5].map(s=>( ))}
{related.length>0 && (

You Might Also Like

Related Pieces

{related.map(p=>)}
)}
); } // ── Orders Page ── function OrdersPage({ user, onBack }) { const [orders,setOrders]=useState([]); const [loading,setLoading]=useState(true); useEffect(()=>{ if(!user)return; sb.from("orders").select("*,order_items(*)").eq("user_id",user.id).order("created_at",{ascending:false}) .then(({data,error})=>{if(!error&&data)setOrders(data);setLoading(false)}); },[user]); if(loading)return
; return (
{e.preventDefault();onBack()}}>← Back

Your Account

My Orders

{orders.length===0?(

No orders yet.

):orders.map(order=>(

Order #{order.id.slice(0,8)}

{new Date(order.created_at).toLocaleDateString('en-IN',{year:'numeric',month:'long',day:'numeric'})}

{order.status} {fmt(order.total)}
{order.order_items&&order.order_items.map(item=>(
{item.product_image&&{item.product_name}}

{item.product_name}

{fmt(item.price)} × {item.quantity}

))}
{order.tracking_id && (

Tracking

{order.tracking_id}

{order.tracking_url && Track →}
)}
))}
); } // ── App ── function App() { const savedCart = (()=> { try { return JSON.parse(localStorage.getItem("basketful_cart")||"[]"); } catch(e) { return []; } })(); const [cart, setCart] = useState(savedCart); const [cartOpen, setCartOpen] = useState(false); const [toasts, setToasts] = useState([]); const [user, setUser] = useState(null); const [loginOpen, setLoginOpen] = useState(false); const [authReady, setAuthReady] = useState(false); const [view, setView] = useState({ page: 'home' }); const [allProducts, setAllProducts] = useState(PRODUCTS); const [wishlist, setWishlist] = useState(new Set()); const [wishlistLoading, setWishlistLoading] = useState(false); useEffect(()=>{ sb.auth.getSession().then(({data:{session}})=>{ setUser(session?.user ?? null); setAuthReady(true); if(session?.user) loadWishlist(session.user.id); }); const {data:{subscription}} = sb.auth.onAuthStateChange((_event, session)=>{ setUser(session?.user ?? null); if(session?.user) loadWishlist(session.user.id); else setWishlist(new Set()); }); return ()=>subscription.unsubscribe(); },[]); useEffect(()=>{ sb.from("products").select("*").order("created_at",{ascending:false}).then(({data,error})=>{ if(!error&&data&&data.length>0){ const supabaseProducts = data.map(row=>({ id: row.id, name: row.name, description: row.description||"", price: row.price, originalPrice: row.original_price||null, image: row.image, category: row.category, subcategory: row.subcategory, tags: row.tags||[], rating: row.rating||0, reviews: row.reviews||0, inStock: row.in_stock!==false, onSale: row.on_sale||false, stock_count: row.stock_count, })); const existingIds = new Set(PRODUCTS.map(p=>p.id)); setAllProducts([...supabaseProducts.filter(p=>!existingIds.has(p.id)),...PRODUCTS]); } }); },[]); const loadWishlist = async (uid) => { const { data } = await sb.from("wishlist").select("product_id").eq("user_id", uid); if (data) setWishlist(new Set(data.map(r => r.product_id))); }; const handleLogin = useCallback(async (u) => { setUser(u); if(u) { loadWishlist(u.id); // Load cart from Supabase const {data} = await sb.from("carts").select("items").eq("user_id", u.id).single(); if(data?.items && Array.isArray(data.items)) { const supItems = data.items.map(i=>({...i,subcategory:""})); // Merge with local cart setCart(prev => { const merged = [...prev]; for(const si of supItems) { const existing = merged.find(m=>m.id===si.id); if(existing) existing.qty = Math.max(existing.qty, si.qty); else merged.push(si); } return merged; }); } } }, []); const handleLogout = useCallback(async () => { await fbAuth.signOut(); await sb.auth.signOut(); setUser(null); setCart([]); setWishlist(new Set()); }, []); const toggleWishlist = useCallback(async (productId) => { if (!user) { setLoginOpen(true); return; } setWishlistLoading(true); if (wishlist.has(productId)) { await sb.from("wishlist").delete().eq("user_id", user.id).eq("product_id", productId); setWishlist(prev => { const n = new Set(prev); n.delete(productId); return n; }); } else { await sb.from("wishlist").insert({ user_id: user.id, product_id: productId }); setWishlist(prev => new Set(prev).add(productId)); } setWishlistLoading(false); }, [user, wishlist]); const addToast = useCallback((name, productId) => { const id = productId || Date.now(); setToasts(p => { const existing = p.find(t => t.productId === id && !t.exiting); if (existing) return p; return [...p, { id: Date.now(), productId: id, name, exiting: false }]; }); setTimeout(() => { setToasts(p => p.map(t => t.productId === id ? { ...t, exiting: true } : t)); setTimeout(() => setToasts(p => p.filter(t => t.productId !== id || !t.exiting)), 300); }, 2200); }, []); const addToCart = useCallback(product=>{ setCart(p=>{const e=p.find(i=>i.id===product.id);if(e)return p.map(i=>i.id===product.id?{...i,qty:i.qty+1}:i);return[...p,{...product,qty:1}]}); addToast(product.name, product.id); },[addToast]); // Sync cart to localStorage + Supabase useEffect(()=>{ localStorage.setItem("basketful_cart", JSON.stringify(cart)); },[cart]); const syncCartToSupabase = useCallback(async (items) => { if(!user) return; const payload = items.map(i=>({id:i.id,name:i.name,image:i.image,price:i.price,qty:i.qty})); await sb.from("carts").upsert({user_id:user.id,items:payload,updated_at:new Date().toISOString()}); },[user]); useEffect(()=>{ if(user && cart.length>=0) syncCartToSupabase(cart); },[cart,user]); const updateQty = useCallback((id,qty)=>{if(qty<=0)setCart(p=>p.filter(i=>i.id!==id));else setCart(p=>p.map(i=>i.id===id?{...i,qty}:i))},[]); const removeFromCart = useCallback(id=>setCart(p=>p.filter(i=>i.id!==id)),[]); const cartCount = cart.reduce((s,i)=>s+i.qty,0); const openCart = useCallback(()=>{setCartOpen(true);document.body.classList.add("no-scroll")},[]); const closeCart = useCallback(()=>{setCartOpen(false);document.body.classList.remove("no-scroll")},[]); const scrollToCollection = useCallback(()=>{document.getElementById("collection")?.scrollIntoView({behavior:"smooth"})},[]); const navigateTo = useCallback((page, opts={}) => { setView({ page, ...opts }); window.scrollTo(0,0); },[]); const saleProducts = allProducts.filter(p=>p.onSale).slice(0,4); const newArrivals = allProducts.filter(p=>!p.onSale).slice(0,4); const currentProduct = view.page==='product' ? allProducts.find(p=>p.id===view.productId) : null; const relatedProducts = currentProduct ? allProducts.filter(p=>p.subcategory===currentProduct.subcategory&&p.id!==currentProduct.id).slice(0,4) : []; return (
setLoginOpen(true)} onLogout={handleLogout} onNavigate={navigateTo} currentView={view.page} products={allProducts}/>
{view.page==='shop' ? ( navigateTo('product',{productId:id})} category={view.category} initialSub={view.subcategory} initialSale={view.onSale} onWishlist={toggleWishlist} wishlist={wishlist}/> ) : view.page==='product' && currentProduct ? ( navigateTo(view.category?'shop':'shop',view.category?{category:view.category}:{})} onWishlist={toggleWishlist} wishlist={wishlist}/> ) : view.page==='orders' ? ( navigateTo('home')}/> ) : view.page==='checkout' ? ( navigateTo('home')} onDone={()=>setCart([])} user={user}/> ) : ( <> navigateTo('product',{productId:id})} onViewAll={()=>navigateTo('shop',{onSale:true})} onWishlist={toggleWishlist} wishlist={wishlist}/> navigateTo('shop',{onSale:true})}/>
navigateTo('product',{productId:id})} onViewAll={()=>navigateTo('shop')} onWishlist={toggleWishlist} wishlist={wishlist}/>
)}
{view.page==='home' &&
} {closeCart();if(!user){setLoginOpen(true);return;}navigateTo('checkout')}} onSaveForLater={(id)=>{toggleWishlist(id);removeFromCart(id)}}/> setLoginOpen(false)} onLogin={handleLogin}/>
); } ReactDOM.createRoot(document.getElementById("root")).render();