Add src/components/ProductCard.tsx

This commit is contained in:
2026-02-04 11:23:01 +00:00
parent cb37f07f34
commit 694eb10ee2

View File

@@ -0,0 +1,73 @@
'use client';
import Image from 'next/image';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
interface StripeProduct {
id: string;
name: string;
description: string | null;
images: string[];
default_price: {
id: string;
unit_amount: number;
currency: string;
} | null;
metadata: Record<string, string>;
}
interface ProductCardProps {
product: StripeProduct;
onCheckout: (productId: string, priceId: string) => void;
}
export default function ProductCard({ product, onCheckout }: ProductCardProps) {
const formatPrice = (amount: number, currency: string) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currency.toUpperCase(),
}).format(amount / 100);
};
return (
<Card className="flex flex-col h-full overflow-hidden hover:shadow-lg transition-shadow">
{product.images[0] && (
<div className="relative aspect-square overflow-hidden">
<Image
src={product.images[0]}
alt={product.name}
fill
className="object-cover hover:scale-105 transition-transform duration-300"
/>
</div>
)}
<CardHeader className="flex-none">
<CardTitle className="line-clamp-1">{product.name}</CardTitle>
{product.default_price && (
<p className="text-2xl font-bold text-primary">
{formatPrice(product.default_price.unit_amount, product.default_price.currency)}
</p>
)}
</CardHeader>
<CardContent className="flex-1">
{product.description && (
<CardDescription className="line-clamp-3">{product.description}</CardDescription>
)}
</CardContent>
<CardFooter>
<Button
className="w-full"
onClick={() => {
if (product.default_price) {
onCheckout(product.id, product.default_price.id);
}
}}
disabled={!product.default_price}
>
{product.default_price ? 'Buy Now' : 'Unavailable'}
</Button>
</CardFooter>
</Card>
);
}