Spaces:
Running
Running
import { useState } from "react"; | |
import { useQuery } from "@tanstack/react-query"; | |
import { productsApi, categoriesApi, storesApi } from "@/lib/api"; | |
import logoUrl from "@assets/assets_task_01k3qp9hccec89tp5ht8ee88x5_1756363038_img_1-removebg-preview (1)_1756364677577.png"; | |
import Header from "@/components/layout/header"; | |
import CategoryNav from "@/components/category/category-nav"; | |
import ProductGrid from "@/components/product/product-grid"; | |
import StoreCard from "@/components/store/store-card"; | |
import { Button } from "@/components/ui/button"; | |
import { Skeleton } from "@/components/ui/skeleton"; | |
import { Category, Product, Store } from "@/types"; | |
import { Package, ShieldCheck, Star, Truck, CreditCard, HeadphonesIcon } from "lucide-react"; | |
import { LoadingSpinner } from "@/components/ui/spinner"; | |
export default function Home() { | |
const [searchQuery, setSearchQuery] = useState(""); | |
const [selectedCategory, setSelectedCategory] = useState<string>(""); | |
const { data: categories = [], isLoading: categoriesLoading } = useQuery({ | |
queryKey: ['/api/categories'], | |
queryFn: () => categoriesApi.getAll(), | |
}); | |
const { data: featuredProducts = [], isLoading: featuredLoading } = useQuery({ | |
queryKey: ['/api/products/featured'], | |
queryFn: () => productsApi.getFeatured(), | |
}); | |
const { data: stores = [], isLoading: storesLoading } = useQuery({ | |
queryKey: ['/api/stores'], | |
queryFn: () => storesApi.getAll(), | |
}); | |
const { data: searchResults = [], isLoading: searchLoading } = useQuery({ | |
queryKey: ['/api/products', { search: searchQuery, category: selectedCategory }], | |
queryFn: () => productsApi.getAll({ | |
...(searchQuery && { search: searchQuery }), | |
...(selectedCategory && { category: selectedCategory }) | |
}), | |
enabled: !!(searchQuery || selectedCategory), | |
}); | |
const showingResults = searchQuery || selectedCategory; | |
const displayProducts = showingResults ? searchResults : featuredProducts; | |
const isProductsLoading = showingResults ? searchLoading : featuredLoading; | |
return ( | |
<div className="min-h-screen bg-gradient-to-br from-orange-100/40 via-amber-100/30 to-red-100/40"> | |
<Header searchQuery={searchQuery} setSearchQuery={setSearchQuery} /> | |
{/* Hero Section - Enhanced Modern Style */} | |
<section className="py-4 px-2" data-testid="hero-section"> | |
<div className="max-w-full mx-auto px-2"> | |
{/* Hero Banner Card - Enhanced */} | |
<div className="bg-gradient-to-r from-orange-500 to-red-600 rounded-3xl p-4 sm:p-6 mb-4 shadow-xl text-white relative overflow-hidden"> | |
{/* Background pattern */} | |
<div className="absolute inset-0 opacity-10"> | |
<div className="absolute top-0 right-0 w-96 h-96 bg-white rounded-full -translate-y-48 translate-x-48"></div> | |
<div className="absolute bottom-0 left-0 w-64 h-64 bg-white rounded-full translate-y-32 -translate-x-32"></div> | |
</div> | |
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 items-center relative z-10"> | |
<div> | |
<div className="flex items-center mb-6" data-testid="hero-title"> | |
<img | |
src={logoUrl} | |
alt="Shoposphere" | |
className="h-16 w-auto mr-6 drop-shadow-lg" | |
/> | |
<div> | |
<h1 className="text-4xl lg:text-5xl font-bold mb-2"> | |
Discover Amazing Products | |
</h1> | |
<p className="text-xl opacity-90">from trusted sellers worldwide</p> | |
</div> | |
</div> | |
<div className="flex flex-col sm:flex-row gap-4"> | |
<Button className="bg-gradient-to-r from-orange-500 to-red-500 text-white hover:from-orange-600 hover:to-red-600 rounded-xl px-8 py-4 text-lg font-semibold shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105" data-testid="browse-products"> | |
Start Shopping | |
</Button> | |
<Button variant="outline" className="border-2 border-white/80 text-white hover:bg-white hover:text-black backdrop-blur-sm rounded-xl px-8 py-4 text-lg font-semibold shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105" data-testid="view-stores"> | |
Learn more | |
</Button> | |
</div> | |
</div> | |
<div className="hidden lg:block"> | |
<div className="bg-gradient-to-br from-orange-100 to-red-100 rounded-3xl p-8 text-center"> | |
<Package className="h-16 w-16 mx-auto mb-4 text-orange-500" /> | |
<h3 className="text-xl font-semibold text-gray-800 mb-2">Fast Delivery</h3> | |
<p className="text-gray-600">Get your orders delivered quickly</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</section> | |
{/* Category Navigation */} | |
<section className="py-4 bg-gradient-to-br from-orange-50/50 via-amber-50/30 to-red-50/50" data-testid="category-section"> | |
<div className="max-w-full mx-auto px-2 sm:px-3 lg:px-4"> | |
<div className="text-center mb-6"> | |
<h2 className="text-2xl font-bold text-gray-900 mb-2">Shop by Category</h2> | |
<p className="text-gray-600">Find exactly what you're looking for</p> | |
</div> | |
{categoriesLoading ? ( | |
<div className="flex flex-col items-center"> | |
<LoadingSpinner text="Loading categories..." /> | |
<div className="flex justify-center space-x-8 mt-4"> | |
{[...Array(6)].map((_, i) => ( | |
<div key={i} className="flex flex-col items-center"> | |
<Skeleton className="w-16 h-16 rounded-full mb-2" /> | |
<Skeleton className="w-16 h-4" /> | |
</div> | |
))} | |
</div> | |
</div> | |
) : ( | |
<CategoryNav | |
categories={categories} | |
selectedCategory={selectedCategory} | |
onCategorySelect={setSelectedCategory} | |
/> | |
)} | |
</div> | |
</section> | |
{/* Products Section */} | |
<section className="py-8 bg-white" data-testid="products-section"> | |
<div className="max-w-full mx-auto px-2 sm:px-3 lg:px-4"> | |
<div className="text-center mb-6"> | |
<h2 className="text-2xl font-bold text-gray-900 mb-3" data-testid="products-title"> | |
{showingResults ? 'Search Results' : 'Featured Products'} | |
</h2> | |
<p className="text-gray-600 max-w-2xl mx-auto text-sm" data-testid="products-subtitle"> | |
{showingResults ? | |
`${displayProducts.length} products found` : | |
'Quality products from trusted sellers' | |
} | |
</p> | |
</div> | |
{isProductsLoading ? ( | |
<div className="flex flex-col items-center"> | |
<LoadingSpinner text={showingResults ? "Searching products..." : "Loading featured products..."} /> | |
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-4 xl:grid-cols-5 gap-2 sm:gap-3 md:gap-4 mt-4 w-full"> | |
{[...Array(12)].map((_, i) => ( | |
<div key={i} className="glass-card rounded-2xl p-4"> | |
<Skeleton className="aspect-square w-full mb-4 rounded-xl" /> | |
<Skeleton className="h-4 w-3/4 mb-2" /> | |
<Skeleton className="h-4 w-1/2 mb-2" /> | |
<Skeleton className="h-6 w-1/4" /> | |
</div> | |
))} | |
</div> | |
</div> | |
) : ( | |
<ProductGrid products={displayProducts} /> | |
)} | |
</div> | |
</section> | |
{/* All Stores Section */} | |
<section className="py-8 bg-gradient-to-br from-orange-50/30 via-amber-50/20 to-red-50/30" data-testid="stores-section"> | |
<div className="max-w-full mx-auto px-2 sm:px-3 lg:px-4"> | |
<div className="text-center mb-8"> | |
<h2 className="text-4xl font-bold text-gray-900 mb-4" data-testid="stores-title"> | |
🏪 Trusted Stores | |
</h2> | |
<p className="text-gray-600 max-w-3xl mx-auto text-lg" data-testid="stores-subtitle"> | |
Explore our network of verified sellers and their unique collections. Each store is carefully vetted to ensure quality and reliability. | |
</p> | |
<div className="flex items-center justify-center mt-4 space-x-6"> | |
<div className="flex items-center"> | |
<ShieldCheck className="h-5 w-5 text-green-500 mr-2" /> | |
<span className="text-sm text-gray-600">Verified Sellers</span> | |
</div> | |
<div className="flex items-center"> | |
<CreditCard className="h-5 w-5 text-blue-500 mr-2" /> | |
<span className="text-sm text-gray-600">Secure Payments</span> | |
</div> | |
<div className="flex items-center"> | |
<Star className="h-5 w-5 text-yellow-500 mr-2" /> | |
<span className="text-sm text-gray-600">Quality Guaranteed</span> | |
</div> | |
</div> | |
</div> | |
{storesLoading ? ( | |
<div className="flex flex-col items-center"> | |
<LoadingSpinner text="Loading stores..." /> | |
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 gap-4 mt-4 w-full"> | |
{[...Array(6)].map((_, i) => ( | |
<div key={i} className="glass-card rounded-2xl p-6"> | |
<Skeleton className="h-32 w-full mb-4 rounded-xl" /> | |
<div className="flex items-center space-x-4"> | |
<Skeleton className="w-16 h-16 rounded-full" /> | |
<div className="flex-1"> | |
<Skeleton className="h-6 w-3/4 mb-2" /> | |
<Skeleton className="h-4 w-full" /> | |
</div> | |
</div> | |
</div> | |
))} | |
</div> | |
</div> | |
) : stores.length > 0 ? ( | |
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-5 gap-4"> | |
{stores.map((store: Store) => ( | |
<StoreCard key={store.id} store={store} /> | |
))} | |
</div> | |
) : ( | |
<div className="text-center py-12"> | |
<p className="text-muted-foreground" data-testid="no-stores"> | |
No stores available at the moment. | |
</p> | |
</div> | |
)} | |
</div> | |
</section> | |
{/* Why Choose Shoposphere Section - Moved to Bottom */} | |
<section className="py-8 bg-gradient-to-br from-orange-100/40 via-amber-100/30 to-red-100/40" data-testid="features-section"> | |
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> | |
<div className="text-center mb-8"> | |
<h2 className="text-2xl font-bold text-gray-900 mb-3">Why Choose Shoposphere?</h2> | |
<p className="text-gray-600 max-w-2xl mx-auto">Experience the best of online shopping with our premium features</p> | |
</div> | |
<div className="grid grid-cols-1 md:grid-cols-3 gap-6"> | |
<div className="text-center p-6 rounded-xl bg-white/70 hover:bg-white/90 transition-all duration-300"> | |
<div className="w-16 h-16 mx-auto mb-4 bg-gradient-to-r from-orange-500 to-red-500 rounded-full flex items-center justify-center"> | |
<Truck className="h-8 w-8 text-white" /> | |
</div> | |
<h3 className="text-lg font-semibold text-gray-900 mb-3">Fast Delivery</h3> | |
<p className="text-gray-600 text-sm">Get your orders delivered quickly with our express shipping network</p> | |
</div> | |
<div className="text-center p-6 rounded-xl bg-white/70 hover:bg-white/90 transition-all duration-300"> | |
<div className="w-16 h-16 mx-auto mb-4 bg-gradient-to-r from-orange-500 to-red-500 rounded-full flex items-center justify-center"> | |
<ShieldCheck className="h-8 w-8 text-white" /> | |
</div> | |
<h3 className="text-lg font-semibold text-gray-900 mb-3">Secure Shopping</h3> | |
<p className="text-gray-600 text-sm">Your payments and personal data are protected with advanced security</p> | |
</div> | |
<div className="text-center p-6 rounded-xl bg-white/70 hover:bg-white/90 transition-all duration-300"> | |
<div className="w-16 h-16 mx-auto mb-4 bg-gradient-to-r from-orange-500 to-red-500 rounded-full flex items-center justify-center"> | |
<HeadphonesIcon className="h-8 w-8 text-white" /> | |
</div> | |
<h3 className="text-lg font-semibold text-gray-900 mb-3">24/7 Support</h3> | |
<p className="text-gray-600 text-sm">Our customer service team is always ready to help you</p> | |
</div> | |
</div> | |
</div> | |
</section> | |
</div> | |
); | |
} | |