File size: 7,242 Bytes
b89a86e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1684141
b89a86e
1684141
 
 
 
 
b89a86e
 
 
 
 
 
 
 
1684141
b89a86e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1684141
 
 
 
 
 
 
 
 
b89a86e
1684141
b89a86e
 
1684141
 
 
 
 
 
 
 
 
 
 
 
b89a86e
 
1684141
b89a86e
1684141
b89a86e
 
 
 
1684141
b89a86e
 
 
 
 
 
1684141
 
 
b89a86e
 
1684141
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b89a86e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
import { Link, useLocation } from "wouter";
import { useCart } from "@/hooks/use-cart";
import { useAuth } from "@/hooks/use-auth";
import { Product } from "@/types";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Heart } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
import { ShoppingCart, Star, Store } from "lucide-react";
import { useToast } from "@/hooks/use-toast";

interface ProductCardProps {
  product: Product;
}

export default function ProductCard({ product }: ProductCardProps) {
  const { addItem } = useCart();
  const { toast } = useToast();
  const { isAuthenticated } = useAuth();
  const [, setLocation] = useLocation();

  const handleAddToCart = async (e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    
    if (!isAuthenticated) {
      toast({
        title: "Login Required",
        description: "Please sign in to add items to your cart.",
        action: (
          <Button 
            variant="outline" 
            size="sm" 
            onClick={() => setLocation('/auth')}
          >
            Sign In
          </Button>
        ),
      });
      return;
    }
    
    try {
      await addItem(product.id, 1);
      toast({
        title: "Added to cart",
        description: `${product.title} has been added to your cart.`,
      });
    } catch (error) {
      toast({
        variant: "destructive",
        title: "Error",
        description: "Failed to add item to cart. Please try again.",
      });
    }
  };

  const discountPercentage = product.originalPrice 
    ? Math.round((1 - parseFloat(product.price) / parseFloat(product.originalPrice)) * 100)
    : 0;

  return (
    <Link href={`/product/${product.id}`}>
      <Card className="group cursor-pointer bg-gradient-to-b from-white to-orange-50/20 rounded-2xl shadow-sm hover:shadow-xl transition-all duration-300 border-0 overflow-hidden h-full hover:scale-[1.02] transform" data-testid={`product-card-${product.id}`}>
        {/* Product Image */}
        <div className="aspect-[4/5] bg-gradient-to-br from-orange-50/50 to-amber-50/60 overflow-hidden relative rounded-xl m-3 mb-4">
          {/* Wishlist Heart */}
          <button className="absolute top-3 right-3 z-10 p-2 bg-white/80 backdrop-blur-sm rounded-full shadow-sm hover:bg-white transition-all duration-200 hover:scale-110" onClick={(e) => { e.preventDefault(); e.stopPropagation(); }} data-testid={`wishlist-${product.id}`}>
            <Heart className="w-4 h-4 text-gray-400 hover:text-red-500 transition-colors" />
          </button>
          {product.images && product.images.length > 0 ? (
            <img
              src={product.images[0]}
              alt={product.title}
              className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
              data-testid={`product-image-${product.id}`}
            />
          ) : (
            <div className="w-full h-full bg-gradient-to-br from-orange-50 to-red-50 flex items-center justify-center">
              <span className="text-gray-400 text-sm">No Image</span>
            </div>
          )}
          
          {/* Discount Badge */}
          {discountPercentage > 0 && (
            <Badge 
              className="absolute top-3 left-3 bg-gradient-to-r from-red-500 to-pink-500 text-white border-0 rounded-full px-2 py-1 text-xs font-medium"
              data-testid={`discount-badge-${product.id}`}
            >
              -{discountPercentage}%
            </Badge>
          )}
        </div>

        <CardContent className="p-4 pt-0 flex flex-col flex-grow">
          {/* Seller Info */}
          {(product as any).seller && (
            <div className="flex items-center gap-2 mb-2">
              <Store className="w-3 h-3 text-gray-400" />
              <span className="text-xs text-gray-500 truncate">{(product as any).seller.username}</span>
            </div>
          )}
          
          {/* Product Title */}
          <h3 className="font-semibold text-gray-800 mb-2 line-clamp-2 text-sm leading-relaxed" data-testid={`product-title-${product.id}`}>
            {product.title}
          </h3>
          
          {/* Rating */}
          <div className="flex items-center gap-1 mb-3">
            <div className="flex items-center">
              <Star className="w-3 h-3 fill-yellow-400 text-yellow-400" />
              <Star className="w-3 h-3 fill-yellow-400 text-yellow-400" />
              <Star className="w-3 h-3 fill-yellow-400 text-yellow-400" />
              <Star className="w-3 h-3 fill-yellow-400 text-yellow-400" />
              <Star className="w-3 h-3 fill-gray-200 text-gray-200" />
            </div>
            <span className="text-xs text-gray-500 ml-1">(4.0)</span>
          </div>

          {/* Price */}
          <div className="mb-3 mt-auto">
            <div className="flex items-baseline space-x-2">
              <span className="text-lg font-bold text-gray-900" data-testid={`product-price-${product.id}`}>
                ₹{parseFloat(product.price).toFixed(2)}
              </span>
              {product.originalPrice && (
                <span 
                  className="text-xs text-gray-400 line-through"
                  data-testid={`original-price-${product.id}`}
                >
                  ₹{parseFloat(product.originalPrice).toFixed(2)}
                </span>
              )}
            </div>
            {discountPercentage > 0 && (
              <p className="text-xs text-green-600 font-medium">Save ₹{(parseFloat(product.originalPrice!) - parseFloat(product.price)).toFixed(2)}</p>
            )}
          </div>
          
          {/* Quick Actions */}
          <div className="flex gap-2">
            <Button
              size="sm"
              onClick={handleAddToCart}
              className="flex-1 bg-gradient-to-r from-orange-500 to-red-500 hover:from-orange-600 hover:to-red-600 text-white border-0 rounded-xl py-2 font-medium text-xs shadow-sm hover:shadow-md transition-all duration-300 hover:scale-105"
              data-testid={`add-to-cart-${product.id}`}
            >
              <ShoppingCart className="w-3 h-3 mr-1" />
              Add to Cart
            </Button>
          </div>
          
          {/* Trust Elements */}
          <div className="flex items-center justify-between mt-2 text-xs text-gray-500">
            <span className="flex items-center gap-1">
              <div className="w-2 h-2 bg-green-500 rounded-full"></div>
              In Stock
            </span>
            <span>Free Shipping</span>
          </div>

          {/* Stock Info */}
          {product.stock <= 5 && product.stock > 0 && (
            <p className="text-xs text-orange-500 mt-2 font-medium" data-testid={`stock-warning-${product.id}`}>
              Only {product.stock} left in stock
            </p>
          )}
          
          {product.stock === 0 && (
            <p className="text-xs text-red-500 mt-2 font-medium" data-testid={`out-of-stock-${product.id}`}>
              Out of stock
            </p>
          )}
        </CardContent>
      </Card>
    </Link>
  );
}