Spaces:
Running
Running
| import React, { useState, useEffect } from 'react'; | |
| import { BrowserRouter as Router, Routes, Route, useLocation, useNavigate } from 'react-router-dom'; | |
| import { Toaster } from '@/components/ui/toaster'; | |
| import { useToast } from '@/components/ui/use-toast'; | |
| import Header from '@/components/Header'; | |
| import Footer from '@/components/Footer'; | |
| import HomePage from '@/pages/HomePage'; | |
| import ProductsPage from '@/pages/ProductsPage'; | |
| import ProductDetailPage from '@/pages/ProductDetailPage'; | |
| import LoginPage from '@/pages/LoginPage'; | |
| import SignUpPage from '@/pages/SignUpPage'; | |
| import CartPage from '@/pages/CartPage'; | |
| import CheckoutPage from '@/pages/CheckoutPage'; | |
| import ContactUsPage from '@/pages/ContactUsPage'; | |
| import ProductCategoriesPage from '@/pages/ProductCategoriesPage'; | |
| import AboutUsPage from '@/pages/AboutUsPage'; | |
| import TermsPage from '@/pages/TermsPage.jsx'; // Corrected import path | |
| import PrivacyPage from '@/pages/PrivacyPage'; | |
| import RefundPage from '@/pages/RefundPage'; | |
| import ShippingPage from '@/pages/ShippingPage'; | |
| import ProfilePage from '@/pages/ProfilePage'; | |
| import OrderConfirmationPage from '@/pages/OrderConfirmationPage'; // Add this line | |
| import WhatsAppButton from '@/components/WhatsAppButton'; | |
| import ScrollToTopButton from '@/components/ScrollToTopButton'; | |
| import FloatingCartButton from '@/components/FloatingCartButton'; | |
| import { motion, useAnimation } from 'framer-motion'; | |
| import { useInView } from 'react-intersection-observer'; | |
| import { Button } from '@/components/ui/button'; | |
| import { supabase } from '@/lib/supabaseClient'; | |
| import SpiceParticlesBg from "@/components/SpiceParticlesBg"; | |
| const AnimatedSection = ({ children, className }) => { | |
| const controls = useAnimation(); | |
| const [ref, inView] = useInView({ | |
| triggerOnce: true, | |
| threshold: 0.1, | |
| }); | |
| useEffect(() => { | |
| if (inView) { | |
| controls.start("visible"); | |
| } | |
| }, [controls, inView]); | |
| return ( | |
| <motion.div | |
| ref={ref} | |
| initial="hidden" | |
| animate={controls} | |
| variants={{ | |
| visible: { opacity: 1, y: 0, transition: { duration: 0.6, ease: "easeOut" } }, | |
| hidden: { opacity: 0, y: 50 }, | |
| }} | |
| className={className} | |
| > | |
| {children} | |
| </motion.div> | |
| ); | |
| }; | |
| const ScrollToTopManager = () => { | |
| const { pathname } = useLocation(); | |
| useEffect(() => { | |
| window.scrollTo({ top: 0, behavior: 'smooth' }); | |
| }, [pathname]); | |
| return null; | |
| }; | |
| const App = () => { | |
| const { toast } = useToast(); | |
| const navigate = useNavigate(); | |
| const location = useLocation(); | |
| const logoUrl = "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/ff7ca0fbd52106cb7f55ba339750f0cd.png"; | |
| const defaultProductImage = "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/1bd6b109ca23886a2bfc7cdef7b819d5.jpg"; | |
| const specialProductImage = "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/special_product_placeholder.jpg"; | |
| const initialProducts = [ | |
| { id: "1", name: "Dal Ka Masala", description: "Aromatic blend for lentil dishes.", price: 100, image: "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/db354947c6ab22e5f0395748cb5baec3.jpg", tags: ["Best Seller"], category: "Spices", weight: "100g", origin: "Rajasthan, India", ingredients: "Coriander, Cumin, Turmeric, Red Chili, Asafoetida, Salt", usage: "Add 1-2 teaspoons to dal while cooking for authentic flavor" }, | |
| { id: "2", name: "Sambar Masala", description: "Authentic South Indian flavor.", price: 90, image: "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/663378930e4f15229c18592432854be4.jpg", tags: ["SALE"], category: "Spices", weight: "100g", origin: "Tamil Nadu, India", ingredients: "Coriander, Fenugreek, Mustard Seeds, Curry Leaves, Red Chili", usage: "Mix 1 tablespoon in sambar or rasam for traditional taste" }, | |
| { id: "3", name: "Shikanji Masala", description: "Refreshing spice for lemonade.", price: 80, image: "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/dc988d79396863101dafa853633b1648.jpg", tags: [], category: "Spices", weight: "100g", origin: "North India", ingredients: "Black Salt, Cumin, Mint, Black Pepper, Citric Acid", usage: "Add 1/2 teaspoon to lemonade for a refreshing summer drink" }, | |
| { id: "4", name: "Chat Masala", description: "Tangy and spicy street food seasoning.", price: 90, image: "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/16be03e66909cc3cde0e5a070c5e2b03.jpg", tags: ["15% OFF"], category: "Spices", weight: "100g", origin: "Delhi, India", ingredients: "Amchur (Dried Mango), Black Salt, Cumin, Coriander, Ginger", usage: "Sprinkle over fruits, salads, or chaat for a tangy kick" }, | |
| { id: "5", name: "Garam Masala", description: "Warm, aromatic all-purpose spice.", price: 100, image: "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/f63dd4c4435a614092696c643557767b.jpg", tags: ["Best Seller"], category: "Spices", weight: "50g", origin: "Punjab, India", ingredients: "Cardamom, Cinnamon, Cloves, Black Pepper, Nutmeg, Bay Leaf", usage: "Add to curries, stews, and rice dishes at the end of cooking" }, | |
| { id: "6", name: "Pav Bhaji Masala", description: "Rich blend for a Mumbai classic.", price: 140, image: "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/08ae4985da9e07006f7f2e16aa4de66c.jpg", tags: [], category: "Spices", weight: "100g", origin: "Maharashtra, India", ingredients: "Coriander, Cumin, Red Chili, Dried Mango, Fennel Seeds", usage: "Mix 2 tablespoons into vegetable mash for authentic pav bhaji" }, | |
| // Removed Premium Almonds, Organic Cashews, Maharaja Chai Blend | |
| ]; | |
| const [products, setProducts] = useState(initialProducts); | |
| const [cart, setCart] = useState([]); | |
| const [searchTerm, setSearchTerm] = useState(''); | |
| const [selectedCategory, setSelectedCategory] = useState(null); | |
| const [session, setSession] = useState(null); | |
| useEffect(() => { | |
| const storedCart = localStorage.getItem('desiBitesCart'); | |
| if (storedCart) { | |
| setCart(JSON.parse(storedCart)); | |
| } | |
| supabase.auth.getSession().then(({ data: { session } }) => { | |
| setSession(session); | |
| }); | |
| const { data: { subscription } } = supabase.auth.onAuthStateChange( | |
| (_event, session) => { | |
| setSession(session); | |
| } | |
| ); | |
| return () => subscription.unsubscribe(); | |
| }, []); | |
| useEffect(() => { | |
| localStorage.setItem('desiBitesCart', JSON.stringify(cart)); | |
| }, [cart]); | |
| const handleAddToCart = (product, quantity = 1) => { | |
| setCart(prevCart => { | |
| const existingProduct = prevCart.find(item => item.id === product.id); | |
| if (existingProduct) { | |
| return prevCart.map(item => | |
| item.id === product.id ? { ...item, quantity: item.quantity + quantity } : item | |
| ); | |
| } | |
| return [...prevCart, { ...product, quantity }]; | |
| }); | |
| toast({ | |
| title: `🌶️ ${product.name} Added!`, | |
| description: `${quantity} item(s) successfully added to your cart.`, | |
| duration: 3000, | |
| className: "bg-green-600 border-green-700 text-white toast-success-theme", | |
| action: ( | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| className="ml-auto bg-green-700 hover:bg-green-800 text-white border-green-500" | |
| onClick={() => navigate('/cart')} | |
| > | |
| View Cart | |
| </Button> | |
| ), | |
| }); | |
| }; | |
| const handleUpdateQuantity = (productId, quantity) => { | |
| setCart(prevCart => | |
| prevCart.map(item => | |
| item.id === productId ? { ...item, quantity: Math.max(0, quantity) } : item | |
| ).filter(item => item.quantity > 0) | |
| ); | |
| }; | |
| const handleRemoveFromCart = (productId) => { | |
| setCart(prevCart => prevCart.filter(item => item.id !== productId)); | |
| toast({ | |
| title: `🗑️ Item Removed`, | |
| description: "Successfully removed from your cart.", | |
| variant: "destructive", | |
| duration: 2000, | |
| className: "bg-red-600 border-red-700 text-white toast-destructive-theme", | |
| }); | |
| }; | |
| const handleSearch = (term) => { | |
| setSearchTerm(term.toLowerCase()); | |
| setSelectedCategory(null); | |
| }; | |
| const handleCategorySelect = (category) => { | |
| setSelectedCategory(category); | |
| setSearchTerm(''); | |
| toast({ | |
| title: `🌶️ Category: ${category}`, | |
| description: `Showing products from ${category}.`, | |
| duration: 3000, | |
| className: "toast-info-theme", | |
| }); | |
| }; | |
| // Listen for custom event to select spices category | |
| useEffect(() => { | |
| const handleSelectSpicesCategory = () => { | |
| handleCategorySelect('Spices'); | |
| }; | |
| window.addEventListener('selectSpicesCategory', handleSelectSpicesCategory); | |
| return () => window.removeEventListener('selectSpicesCategory', handleSelectSpicesCategory); | |
| }, []); | |
| const filteredProducts = products.filter(product => { | |
| const matchesSearchTerm = product.name.toLowerCase().includes(searchTerm); | |
| const matchesCategory = selectedCategory ? product.category === selectedCategory : true; | |
| return matchesSearchTerm && matchesCategory; | |
| }); | |
| const heroImages = [ | |
| "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/ca8c4d496de1a5c8f2581319c0fb73fa.jpg", | |
| "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/b8eec8d2a26b01e00bfd1e15ab86a6e2.jpg", | |
| "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/23bd20088098dd61c2444f85dceac2ca.jpg", | |
| "https://storage.googleapis.com/hostinger-horizons-assets-prod/0d2dbf2b-b616-4ee8-a20e-de4e4a4d280c/b27cf798f5c9406e465423e71ca5e8f0.jpg" | |
| ]; | |
| const cartItemCount = cart.reduce((sum, item) => sum + item.quantity, 0); | |
| const HEADER_MOBILE_HEIGHT = 80; | |
| const HEADER_SM_HEIGHT = 90; | |
| const HEADER_MD_HEIGHT = 100; | |
| const [currentHeaderHeight, setCurrentHeaderHeight] = useState(HEADER_MOBILE_HEIGHT); | |
| useEffect(() => { | |
| const updateHeaderHeight = () => { | |
| if (window.innerWidth < 640) { | |
| setCurrentHeaderHeight(HEADER_MOBILE_HEIGHT); | |
| } else if (window.innerWidth < 768) { | |
| setCurrentHeaderHeight(HEADER_SM_HEIGHT); | |
| } else { | |
| setCurrentHeaderHeight(HEADER_MD_HEIGHT); | |
| } | |
| }; | |
| updateHeaderHeight(); | |
| window.addEventListener('resize', updateHeaderHeight); | |
| return () => window.removeEventListener('resize', updateHeaderHeight); | |
| }, []); | |
| return ( | |
| <> | |
| <ScrollToTopManager /> | |
| <div className="min-h-screen text-stone-800 font-serif flex flex-col app-background-theme"> | |
| <SpiceParticlesBg /> | |
| <Toaster /> | |
| <Header | |
| logoUrl={logoUrl} | |
| cartItemCount={cartItemCount} | |
| onCategorySelect={handleCategorySelect} | |
| headerHeight={currentHeaderHeight} | |
| session={session} | |
| setSession={setSession} | |
| /> | |
| <main | |
| className="flex-grow" | |
| style={{ | |
| paddingTop: `${currentHeaderHeight}px` | |
| }} | |
| > | |
| <Routes> | |
| <Route path="/" element={<HomePage heroImages={heroImages} onAddToCart={handleAddToCart} initialProducts={initialProducts} cartItems={cart} onUpdateQuantity={handleUpdateQuantity} />} /> | |
| <Route | |
| path="/products" | |
| element={ | |
| <AnimatedSection> | |
| <ProductsPage | |
| products={filteredProducts} | |
| onAddToCart={handleAddToCart} | |
| searchTerm={searchTerm} | |
| onSearchChange={handleSearch} | |
| cartItemCount={cartItemCount} | |
| selectedCategory={selectedCategory} | |
| cartItems={cart} | |
| onUpdateQuantity={handleUpdateQuantity} | |
| /> | |
| </AnimatedSection> | |
| } | |
| /> | |
| <Route | |
| path="/product/:productId" | |
| element={ | |
| <AnimatedSection> | |
| <ProductDetailPage | |
| products={products} | |
| onAddToCart={handleAddToCart} | |
| cartItems={cart} | |
| onUpdateQuantity={handleUpdateQuantity} | |
| /> | |
| </AnimatedSection> | |
| } | |
| /> | |
| <Route path="/product-categories" element={<AnimatedSection><ProductCategoriesPage onCategorySelect={handleCategorySelect} /></AnimatedSection>} /> | |
| <Route path="/login" element={<AnimatedSection><LoginPage setSession={setSession} /></AnimatedSection>} /> | |
| <Route path="/signup" element={<AnimatedSection><SignUpPage /></AnimatedSection>} /> | |
| <Route | |
| path="/cart" | |
| element={ | |
| <AnimatedSection> | |
| <CartPage | |
| cartItems={cart} | |
| onUpdateQuantity={handleUpdateQuantity} | |
| onRemoveFromCart={handleRemoveFromCart} | |
| onAddToCart={handleAddToCart} | |
| /> | |
| </AnimatedSection> | |
| } | |
| /> | |
| <Route | |
| path="/checkout" | |
| element={ | |
| <AnimatedSection> | |
| <CheckoutPage | |
| cartItems={cart} | |
| onUpdateQuantity={handleUpdateQuantity} | |
| onRemoveFromCart={handleRemoveFromCart} | |
| /> | |
| </AnimatedSection> | |
| } | |
| /> | |
| <Route path="/contact" element={<AnimatedSection><ContactUsPage companyName="Desi Bites" brandName="Taste Rider" /></AnimatedSection>} /> | |
| <Route path="/about-us" element={<AnimatedSection><AboutUsPage /></AnimatedSection>} /> | |
| <Route path="/terms" element={<AnimatedSection><TermsPage /></AnimatedSection>} /> | |
| <Route path="/privacy" element={<AnimatedSection><PrivacyPage /></AnimatedSection>} /> | |
| <Route path="/refund" element={<AnimatedSection><RefundPage /></AnimatedSection>} /> | |
| <Route path="/shipping" element={<AnimatedSection><ShippingPage /></AnimatedSection>} /> | |
| <Route path="/profile" element={<AnimatedSection><ProfilePage session={session} setSession={setSession} /></AnimatedSection>} /> | |
| <Route path="/order-confirmation" element={<AnimatedSection><OrderConfirmationPage /></AnimatedSection>} /> | |
| </Routes> | |
| </main> | |
| <Footer logoUrl={logoUrl} companyName="Desi Bites" /> | |
| <WhatsAppButton phoneNumber="+919997539999" /> | |
| <ScrollToTopButton /> | |
| {/* Add FloatingCartButton to all pages except cart and checkout */} | |
| {location.pathname !== '/cart' && location.pathname !== '/checkout' && ( | |
| <FloatingCartButton cartItemCount={cartItemCount} /> | |
| )} | |
| </div> | |
| </> | |
| ); | |
| }; | |
| const AppWrapper = () => ( | |
| <Router> | |
| <App /> | |
| </Router> | |
| ); | |
| export default AppWrapper; |