Loading...
"use client"import { useState, useEffect } from "react"import { useRouter, useParams } from "next/navigation"import { Button } from "@/components/ui/button"import { Badge } from "@/components/ui/badge"import { Card } from "@/components/ui/card"import { Star, Plus, Minus, Truck, RotateCcw, Shield, CreditCard, MessageSquare, ThumbsUp, ThumbsDown, EditIcon, Trash2,} from "lucide-react"import Image from "next/image"import { useCart } from "@/lib/cart-context"import { toast } from "sonner"import ShopLoader from "@/components/shopora-loader"import { products, mockReviews } from "@/lib/mock-data"import { useAuth } from "@/lib/auth-context"import Link from "next/link"// Helper function to format description into pointsconst formatDescriptionAsPoints = (description) => { const sentences = description.split(/(?<=[.!?])\s+/).filter(Boolean) return ( <ul className="list-disc list-inside space-y-2 text-lg text-gray-700 dark:text-gray-300 mb-6"> {sentences.map((sentence, index) => ( <li key={index}>{sentence.trim()}</li> ))} </ul> )}// Helper function for rating breakdown (mock data)const getRatingBreakdown = () => { return { 5: 65, 4: 25, 3: 8, 2: 2, 1: 0 }}export default function ProductDetailPage() { const router = useRouter() const params = useParams() const productId = Number.parseInt(params.id) const [product, setProduct] = useState(null) const [quantity, setQuantity] = useState(0) const [newReview, setNewReview] = useState({ rating: 0, comment: "" }) const [isLoading, setIsLoading] = useState(true) const { addToCart } = useCart() const { user } = useAuth() useEffect(() => { setIsLoading(true) const foundProduct = products.find((p) => p.id === productId) if (foundProduct) { setProduct(foundProduct) setQuantity(0) } else { router.push("/products") toast.error("Product not found!") } setIsLoading(false) }, [productId, router]) const updateQuantity = (change) => { if (!user) { toast.info("Please log in or sign up to modify quantities.") return } setQuantity((prev) => Math.max(0, prev + change)) } const handleAddToCart = () => { if (!user) { toast.info("Please log in or sign up to add items to your cart.") return } if (quantity > 0 && product) { addToCart({ ...product, quantity }) toast.success(`Added ${quantity} x ${product.name} to cart!`) setQuantity(0) } else { toast.error("Please select a quantity to add to cart.") } } const handleSubmitReview = (e) => { e.preventDefault() if (!user) { toast.info("Please log in or sign up to submit a review.") return } if (newReview.rating === 0 || !newReview.comment.trim()) { toast.error("Please provide a rating and a comment for your review.") return } console.log("Submitting review:", newReview) toast.success("Review submitted successfully!") setNewReview({ rating: 0, comment: "" }) } if (isLoading) { return ( <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 to-blue-50 dark:from-slate-900 dark:to-blue-900"> <ShopLoader message="Loading product details..." size="lg" /> </div> ) } if (!product) { return ( <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 to-blue-50 dark:from-slate-900 dark:to-blue-900 py-8"> <div className="container mx-auto px-4 text-center"> <div className="bg-white/90 dark:bg-slate-800/90 backdrop-blur-sm rounded-2xl shadow-2xl p-16 max-w-md mx-auto border border-gray-200 dark:border-gray-700"> <div className="text-8xl mb-6">🔍</div> <h1 className="text-3xl font-bold mb-4 text-gray-800 dark:text-white">Product Not Found</h1> <p className="text-gray-600 dark:text-gray-300 mb-8"> The product you are looking for does not exist or has been removed. </p> <Button onClick={() => router.push("/products")} className="bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white font-bold px-8 py-4 rounded-full shadow-xl transform hover:scale-105 transition-all duration-300" > 🛍️ Back to Products </Button> </div> </div> </div> ) } const ratingBreakdown = getRatingBreakdown() return ( <div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-purple-50 dark:from-slate-900 dark:via-blue-900 dark:to-purple-900 py-8"> <div className="container mx-auto px-4"> <Card className="bg-white/90 dark:bg-slate-800/90 backdrop-blur-sm rounded-2xl shadow-2xl overflow-hidden border border-gray-200 dark:border-gray-700 card-glow"> <div className="grid lg:grid-cols-2 gap-8 p-8"> {/* Product Image */} <div className="relative"> <div className="aspect-square rounded-xl overflow-hidden bg-gray-100 dark:bg-gray-800"> <Image src={product.image || "/placeholder.svg"} alt={product.name} width={500} height={500} className="w-full h-full object-cover product-image-hover" /> </div> <Badge className="absolute top-4 left-4 bg-red-500 text-white font-bold shadow-lg">🔥 HOT DEAL</Badge> </div> {/* Product Details */} <div className="space-y-6"> <div> <h1 className="text-3xl lg:text-4xl font-bold mb-4 text-gray-800 dark:text-white">{product.name}</h1> <div className="flex items-center mb-4"> <div className="flex text-yellow-400"> {[...Array(5)].map((_, i) => ( <Star key={i} className={`w-5 h-5 ${i < Math.floor(product.rating) ? "fill-current" : ""}`} /> ))} </div> <span className="ml-2 text-gray-600 dark:text-gray-400"> ({product.rating}) • {product.reviews} reviews </span> </div> <div className="flex items-center gap-4 mb-6"> <span className="text-3xl lg:text-4xl font-bold text-blue-600 dark:text-blue-400"> ₹{(product.price * 83).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ",")} </span> {product.originalPrice && ( <span className="text-xl text-gray-500 line-through"> ₹{(product.originalPrice * 83).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ",")} </span> )} {product.originalPrice && ( <Badge className="bg-green-500 text-white"> Save ₹ {((product.originalPrice - product.price) * 83).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ",")} </Badge> )} </div> {/* Formatted Description */} {formatDescriptionAsPoints(product.description)} </div> {/* Standard Features */} <div className="grid grid-cols-2 gap-4"> {[ { icon: Truck, title: "Free Delivery", desc: "On orders above ₹4,150", color: "green" }, { icon: RotateCcw, title: "Easy Returns", desc: "30-day return policy", color: "blue" }, { icon: Shield, title: "Warranty", desc: "1-year manufacturer warranty", color: "purple" }, { icon: CreditCard, title: "Secure Payment", desc: "100% secure checkout", color: "orange" }, ].map((feature, index) => ( <div key={index} className="flex items-center space-x-3 p-4 bg-gray-50 dark:bg-gray-700 rounded-xl border border-gray-200 dark:border-gray-600" > <div className={`bg-${feature.color}-500 p-2 rounded-full`}> <feature.icon className="w-4 h-4 text-white" /> </div> <div> <div className="font-bold text-gray-800 dark:text-white text-sm">{feature.title}</div> <div className="text-xs text-gray-600 dark:text-gray-400">{feature.desc}</div> </div> </div> ))} </div> {/* Quantity and Add to Cart */} <div className="flex items-center gap-4 p-6 bg-gray-50 dark:bg-gray-800 rounded-xl"> <div className="flex items-center border-2 border-blue-300 dark:border-blue-600 rounded-full bg-white dark:bg-gray-700"> <Button size="sm" variant="ghost" onClick={() => updateQuantity(-1)} className="rounded-full w-10 h-10" disabled={!user} > <Minus className="w-4 h-4" /> </Button> <span className="px-4 py-2 font-bold text-lg min-w-[3rem] text-center">{quantity}</span> <Button size="sm" variant="ghost" onClick={() => updateQuantity(1)} className="rounded-full w-10 h-10" disabled={!user} > <Plus className="w-4 h-4" /> </Button> </div> <Button onClick={handleAddToCart} disabled={quantity === 0 || !user} className="flex-1 bg-gradient-to-r from-blue-600 to-purple-600 hover:from-blue-700 hover:to-purple-700 text-white font-bold py-3 rounded-full shadow-xl transform hover:scale-105 transition-all duration-300" > Add {quantity} to Cart </Button> </div> {product.isCreatedByUser && user && ( <div className="flex gap-4"> <Button variant="outline" className="flex-1 rounded-full bg-transparent"> <EditIcon className="w-4 h-4 mr-2" /> Edit Product </Button> <Button variant="destructive" className="flex-1 rounded-full"> <Trash2 className="w-4 h-4 mr-2" /> Delete Product </Button> </div> )} </div> </div> {/* Reviews Section */} <div className="border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 p-8"> <h3 className="text-2xl font-bold mb-8 text-gray-800 dark:text-white">Customer Reviews & Ratings</h3> <div className="grid lg:grid-cols-2 gap-8 mb-8"> {/* Rating Overview */} <Card className="p-6 bg-white dark:bg-slate-800 rounded-xl shadow-lg border border-gray-200 dark:border-gray-700 card-glow"> <div className="text-center mb-6"> <div className="text-5xl font-bold text-blue-600 dark:text-blue-400 mb-2">{product.rating}</div> <div className="flex justify-center text-yellow-400 mb-2"> {[...Array(5)].map((_, i) => ( <Star key={i} className={`w-6 h-6 ${i < Math.floor(product.rating) ? "fill-current" : ""}`} /> ))} </div> <div className="text-gray-600 dark:text-gray-400">{product.reviews} total reviews</div> </div> <div className="space-y-3"> {[5, 4, 3, 2, 1].map((stars) => { const percentage = ratingBreakdown[stars] return ( <div key={stars} className="flex items-center space-x-3"> <span className="text-sm font-medium w-8 text-gray-700 dark:text-gray-300">{stars}★</span> <div className="flex-1 bg-gray-200 dark:bg-gray-700 rounded-full h-2"> <div className="bg-yellow-400 h-2 rounded-full transition-all duration-300" style={{ width: `${percentage}%` }} ></div> </div> <span className="text-sm text-gray-600 dark:text-gray-400 w-12">{percentage}%</span> </div> ) })} </div> </Card> {/* Add Review Form */} {user && ( <Card className="p-6 bg-white dark:bg-slate-800 rounded-xl shadow-lg border border-gray-200 dark:border-gray-700 card-glow"> <h4 className="text-xl font-bold mb-4 text-gray-800 dark:text-white">Write a Review</h4> <form onSubmit={handleSubmitReview} className="space-y-4"> <div> <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"> Your Rating </label> <div className="flex space-x-1"> {[1, 2, 3, 4, 5].map((star) => ( <Star key={star} className={`w-6 h-6 cursor-pointer transition-colors ${ star <= newReview.rating ? "text-yellow-400 fill-current" : "text-gray-300" }`} onClick={() => setNewReview({ ...newReview, rating: star })} /> ))} </div> </div> <div> <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"> Your Review </label> <textarea className="w-full p-3 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white" rows={4} placeholder="Share your experience with this product..." value={newReview.comment} onChange={(e) => setNewReview({ ...newReview, comment: e.target.value })} ></textarea> </div> <Button type="submit" className="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-lg" > Submit Review </Button> </form> </Card> )} {!user && ( <Card className="p-6 bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-xl shadow-lg card-glow text-center"> <div className="text-2xl mb-2">🔒</div> <h4 className="text-xl font-bold text-blue-800 dark:text-blue-200 mb-2">Login to Write a Review</h4> <p className="text-blue-700 dark:text-blue-300"> Share your thoughts on this product by{" "} <Link href="/auth/login" className="font-bold underline"> logging in </Link>{" "} or{" "} <Link href="/auth/register" className="font-bold underline"> signing up </Link> . </p> </Card> )} </div> {/* Reviews List */} <div className="space-y-6"> <h4 className="text-xl font-bold text-gray-800 dark:text-white">Recent Reviews</h4> {mockReviews.map((review) => ( <Card key={review.id} className="p-6 bg-white dark:bg-slate-800 rounded-xl shadow-lg border border-gray-200 dark:border-gray-700 card-glow" > <div className="flex items-start justify-between mb-4"> <div className="flex items-center space-x-3"> <div className="w-10 h-10 bg-gradient-to-r from-blue-500 to-purple-500 rounded-full flex items-center justify-center text-white font-bold"> {review.user[0]} </div> <div> <div className="flex items-center space-x-2"> <span className="font-bold text-gray-800 dark:text-white">{review.user}</span> </div> <div className="flex items-center space-x-2"> <div className="flex text-yellow-400"> {[...Array(5)].map((_, i) => ( <Star key={i} className={`w-4 h-4 ${i < review.rating ? "fill-current" : ""}`} /> ))} </div> <span className="text-sm text-gray-500">{review.date}</span> </div> </div> </div> <Button variant="ghost" size="sm" className="text-red-500 hover:text-red-700"> <Trash2 className="w-4 h-4" /> </Button> </div> <p className="text-gray-700 dark:text-gray-300 mb-4">{review.comment}</p> <div className="flex items-center space-x-4"> <Button variant="ghost" size="sm" className="text-gray-500 hover:text-blue-600"> <ThumbsUp className="w-4 h-4 mr-1" /> Helpful ({review.helpful}) </Button> <Button variant="ghost" size="sm" className="text-gray-500 hover:text-red-600"> <ThumbsDown className="w-4 h-4 mr-1" /> Unhelpful ({review.unhelpful}) </Button> <Button variant="ghost" size="sm" className="text-gray-500 hover:text-blue-600"> <MessageSquare className="w-4 h-4 mr-1" /> Reply </Button> </div> </Card> ))} </div> </div> </Card> </div> </div> )} keeping design and everything same just change add to cart and remove from cart logic so that one product is added when i click 1 once and so on and same for when i remove
Loading...
"use client"import { useState } from "react"import { useRouter } from "next/navigation"import { Button } from "@/components/ui/button"import { Badge } from "@/components/ui/badge"import { Card, CardContent } from "@/components/ui/card"import { Input } from "@/components/ui/input"import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"import { Plus, Minus, Search, Filter, Heart, EditIcon, Trash2 } from "lucide-react"import Image from "next/image"import { useCart } from "@/lib/cart-context"import { products } from "@/lib/mock-data" // Import products from mock dataimport { useAuth } from "@/lib/auth-context"import { toast } from "sonner"const mockReviews = [ { id: 1, user: "Sarah Chen", rating: 5, comment: "Amazing product! The sound quality is incredible and the battery life is fantastic. Highly recommend!", date: "2024-01-15", helpful: 12, unhelpful: 1, }, { id: 2, user: "Mike Rodriguez", rating: 4, comment: "Great value for money. Works perfectly with my devices. Fast shipping too!", date: "2024-01-10", helpful: 8, unhelpful: 0, }, { id: 3, user: "Emma Wilson", rating: 5, comment: "Exceeded my expectations! The build quality is excellent and it arrived quickly.", date: "2024-01-08", helpful: 15, unhelpful: 2, },]// Helper function to format description into pointsconst formatDescriptionAsPoints = (description) => { const sentences = description.split(/(?<=[.!?])\s+/).filter(Boolean) return ( <ul className="list-disc list-inside space-y-2 text-lg text-gray-700 dark:text-gray-300 mb-6"> {sentences.map((sentence, index) => ( <li key={index}>{sentence.trim()}</li> ))} </ul> )}export default function ProductsPage() { const [quantities, setQuantities] = useState({}) const [searchTerm, setSearchTerm] = useState("") const [categoryFilter, setCategoryFilter] = useState("all") const { addToCart } = useCart() const { user } = useAuth() const router = useRouter() const updateQuantity = (productId, change) => { if (!user) { toast.info("Please log in or sign up to modify quantities.") return } setQuantities((prev) => ({ ...prev, [productId]: Math.max(0, (prev[productId] || 0) + change), })) } const handleAddToCart = (product, quantity) => { if (!user) { toast.info("Please log in or sign up to add items to your cart.") return } if (quantity > 0) { addToCart({ ...product, quantity }) toast.success(`Added ${quantity} x ${product.name} to cart!`) } } const filteredProducts = products.filter((product) => { const matchesSearch = product.name.toLowerCase().includes(searchTerm.toLowerCase()) const matchesCategory = categoryFilter === "all" || product.category.toLowerCase() === categoryFilter.toLowerCase() return matchesSearch && matchesCategory }) return ( <div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-purple-50 dark:from-slate-900 dark:via-blue-900 dark:to-purple-900 py-8"> <div className="container mx-auto px-4"> <div className="text-center mb-12"> <h1 className="text-5xl font-black mb-4 bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent"> 🛍️ PRODUCTS </h1> <p className="text-xl text-gray-600 dark:text-gray-300">Discover amazing deals on premium products!</p> </div> {/* Search and Filter */} <div className="flex flex-col md:flex-row gap-4 mb-8"> <div className="relative flex-1"> <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-5 h-5" /> <Input placeholder="Search products..." value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} className="pl-10 rounded-full border-2 border-blue-300 dark:border-blue-600 focus:border-blue-500 bg-white/90 dark:bg-slate-800/90 backdrop-blur-sm" /> </div> <Select value={categoryFilter} onValueChange={setCategoryFilter}> <SelectTrigger className="w-full md:w-48 rounded-full border-2 border-blue-300 dark:border-blue-600 bg-white/90 dark:bg-slate-800/90 backdrop-blur-sm"> <Filter className="w-4 h-4 mr-2" /> <SelectValue placeholder="Category" /> </SelectTrigger> <SelectContent> <SelectItem value="all">All Categories</SelectItem> <SelectItem value="electronics">Electronics</SelectItem> <SelectItem value="gaming">Gaming</SelectItem> <SelectItem value="accessories">Accessories</SelectItem> </SelectContent> </Select> </div> {/* Products Grid - More Compact Cards */} <div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-4 gap-3 md:gap-4"> {filteredProducts.map((product) => ( <Card key={product.id} className="overflow-hidden shadow-lg transition-all duration-300 bg-white/90 dark:bg-slate-800/90 backdrop-blur-sm rounded-xl border border-gray-200 dark:border-gray-700 card-glow" > <div className="relative w-full h-32 sm:h-40"> <Image src={product.image || "/placeholder.svg"} alt={product.name} fill className="object-cover w-full h-full cursor-pointer hover:scale-110 transition-transform duration-300 rounded-t-xl" onClick={() => router.push(`/products/${product.id}`)} /> <div className="absolute top-1 left-1"> <Button variant="ghost" size="sm" className="w-6 h-6 p-0 bg-white/80 hover:bg-white rounded-full"> <Heart className="w-3 h-3 text-gray-600" /> </Button> </div> <div className="absolute top-1 right-1 flex space-x-1"> {user && ( <> <Button variant="ghost" size="sm" className="w-6 h-6 p-0 bg-white/80 hover:bg-white rounded-full"> <EditIcon className="w-3 h-3 text-gray-600" /> </Button> <Button variant="ghost" size="sm" className="w-6 h-6 p-0 bg-red-500 hover:bg-red-600 rounded-full" > <Trash2 className="w-3 h-3 text-white" /> </Button> </> )} </div> </div> <CardContent className="p-2 space-y-1"> <h3 className="text-xs font-bold cursor-pointer hover:text-blue-600 dark:hover:text-blue-400 line-clamp-2 text-gray-800 dark:text-white min-h-[2rem]" onClick={() => router.push(`/products/${product.id}`)} > {product.name} </h3> <div className="flex flex-wrap gap-1"> {product.tags.map((tag, index) => ( <Badge key={index} className="bg-gray-100 text-gray-800 text-xs px-1 py-0.5 rounded-full text-[10px]" > {tag} </Badge> ))} </div> <div className="flex items-center justify-between pt-1"> <div className="text-sm font-bold text-blue-600 dark:text-blue-400"> ₹{(product.price * 83).toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ",")} </div> <Button size="sm" onClick={() => updateQuantity(product.id, (quantities[product.id] || 0) + 1)} className="bg-blue-600 hover:bg-blue-700 rounded-full w-6 h-6 p-0 shadow-lg" disabled={!user} > <Plus className="w-3 h-3" /> </Button> </div> {quantities[product.id] > 0 && ( <div className="flex items-center justify-between pt-1 border-t border-gray-200 dark:border-gray-600"> <div className="flex items-center space-x-1"> <Button size="sm" variant="outline" onClick={() => updateQuantity(product.id, quantities[product.id] - 1)} className="rounded-full w-5 h-5 p-0" disabled={!user} > <Minus className="w-2.5 h-2.5" /> </Button> <span className="font-bold text-xs">{quantities[product.id]}</span> <Button size="sm" onClick={() => updateQuantity(product.id, quantities[product.id] + 1)} className="bg-blue-600 hover:bg-blue-700 rounded-full w-5 h-5 p-0" disabled={!user} > <Plus className="w-2.5 h-2.5" /> </Button> </div> <Button onClick={() => handleAddToCart(product, quantities[product.id])} size="sm" className="bg-green-600 hover:bg-green-700 text-white rounded-full px-2 py-1 text-xs" disabled={!user} > Add </Button> </div> )} </CardContent> </Card> ))} </div> {filteredProducts.length === 0 && ( <div className="text-center py-16"> <div className="text-6xl mb-4">🔍</div> <h3 className="text-2xl font-bold text-gray-600 dark:text-gray-400 mb-2">No products found</h3> <p className="text-gray-500 dark:text-gray-500">Try adjusting your search or filter criteria</p> </div> )} </div> </div> )}keeping design and everything same just change add to cart and remove from cart logic so that one product is added when i click 1 once and so on and same for when i remove