fuck yeah. daisyui integrated
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
interface ProductCardProps {
|
||||
product: {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
image_url: string;
|
||||
brand: { name: string };
|
||||
category: { name: string };
|
||||
restrictions: string[];
|
||||
offers: Array<{ price: number; vendor: { name: string } }>;
|
||||
};
|
||||
}
|
||||
|
||||
export default function ProductCard({ product }: ProductCardProps) {
|
||||
const [imageError, setImageError] = useState(false);
|
||||
const lowestPrice = Math.min(...product.offers.map(offer => offer.price));
|
||||
|
||||
// Restriction badge component
|
||||
const RestrictionBadge = ({ restriction }: { restriction: string }) => {
|
||||
const restrictionConfig = {
|
||||
NFA: {
|
||||
label: 'NFA',
|
||||
color: 'badge-error',
|
||||
icon: '🔒',
|
||||
tooltip: 'National Firearms Act - Requires special registration'
|
||||
},
|
||||
SBR: {
|
||||
label: 'SBR',
|
||||
color: 'badge-warning',
|
||||
icon: '📏',
|
||||
tooltip: 'Short Barrel Rifle - Requires NFA registration'
|
||||
},
|
||||
SUPPRESSOR: {
|
||||
label: 'Suppressor',
|
||||
color: 'badge-secondary',
|
||||
icon: '🔇',
|
||||
tooltip: 'Sound Suppressor - Requires NFA registration'
|
||||
},
|
||||
FFL_REQUIRED: {
|
||||
label: 'FFL',
|
||||
color: 'badge-info',
|
||||
icon: '🏪',
|
||||
tooltip: 'Federal Firearms License required for purchase'
|
||||
},
|
||||
STATE_RESTRICTIONS: {
|
||||
label: 'State',
|
||||
color: 'badge-warning',
|
||||
icon: '🗺️',
|
||||
tooltip: 'State-specific restrictions may apply'
|
||||
},
|
||||
HIGH_CAPACITY: {
|
||||
label: 'High Cap',
|
||||
color: 'badge-accent',
|
||||
icon: '🥁',
|
||||
tooltip: 'High capacity magazine - check local laws'
|
||||
},
|
||||
SILENCERSHOP_PARTNER: {
|
||||
label: 'SilencerShop',
|
||||
color: 'badge-success',
|
||||
icon: '🤝',
|
||||
tooltip: 'Available through SilencerShop partnership'
|
||||
}
|
||||
};
|
||||
|
||||
const config = restrictionConfig[restriction as keyof typeof restrictionConfig];
|
||||
if (!config) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`badge ${config.color} gap-1 cursor-help`}
|
||||
title={config.tooltip}
|
||||
>
|
||||
<span>{config.icon}</span>
|
||||
<span>{config.label}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card bg-base-100 shadow-lg hover:shadow-xl transition-shadow duration-300 border border-base-300">
|
||||
<figure className="relative">
|
||||
<img
|
||||
src={imageError ? 'https://placehold.co/300x200/6b7280/ffffff?text=No+Image' : product.image_url}
|
||||
alt={product.name}
|
||||
className="w-full h-48 object-cover"
|
||||
onError={() => setImageError(true)}
|
||||
/>
|
||||
{product.restrictions && product.restrictions.length > 0 && (
|
||||
<div className="absolute top-2 left-2 flex flex-wrap gap-1">
|
||||
{product.restrictions.map((restriction) => (
|
||||
<RestrictionBadge key={restriction} restriction={restriction} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</figure>
|
||||
|
||||
<div className="card-body">
|
||||
<h3 className="card-title text-base-content line-clamp-2">{product.name}</h3>
|
||||
<p className="text-base-content/70 text-sm line-clamp-2">{product.description}</p>
|
||||
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<span className="text-sm text-base-content/60">{product.brand.name}</span>
|
||||
<span className="text-lg font-bold text-primary">${lowestPrice.toFixed(2)}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-xs text-base-content/50">{product.category.name}</span>
|
||||
<button className="btn btn-primary btn-sm">
|
||||
View Details
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user