localgreenchain/components/marketplace/PriceDisplay.tsx
Claude b3c2af51bf
Implement marketplace foundation (Agent 9)
Add comprehensive plant trading marketplace with:
- Prisma schema with marketplace models (Listing, Offer, SellerProfile, WishlistItem)
- Service layer for listings, offers, search, and matching
- API endpoints for CRUD operations, search, and recommendations
- Marketplace pages: home, listing detail, create, my-listings, my-offers
- Reusable UI components: ListingCard, ListingGrid, OfferForm, SearchFilters, etc.

Features:
- Browse and search listings by category, price, tags
- Create and manage listings (draft, active, sold, cancelled)
- Make and manage offers on listings
- Seller and buyer views with statistics
- Featured and recommended listings
- In-memory store (ready for database migration via Agent 2)
2025-11-23 03:58:08 +00:00

96 lines
2.1 KiB
TypeScript

interface PriceDisplayProps {
price: number;
currency?: string;
originalPrice?: number;
size?: 'sm' | 'md' | 'lg' | 'xl';
showCurrency?: boolean;
}
const sizeClasses = {
sm: 'text-sm',
md: 'text-lg',
lg: 'text-2xl',
xl: 'text-4xl',
};
export function PriceDisplay({
price,
currency = 'USD',
originalPrice,
size = 'md',
showCurrency = false,
}: PriceDisplayProps) {
const hasDiscount = originalPrice && originalPrice > price;
const discountPercentage = hasDiscount
? Math.round((1 - price / originalPrice) * 100)
: 0;
const formatPrice = (value: number) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currency,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(value);
};
return (
<div className="flex items-baseline gap-2">
<span className={`font-bold text-green-600 ${sizeClasses[size]}`}>
{formatPrice(price)}
</span>
{showCurrency && (
<span className="text-gray-500 text-sm">{currency}</span>
)}
{hasDiscount && (
<>
<span className="text-gray-400 line-through text-sm">
{formatPrice(originalPrice)}
</span>
<span className="px-2 py-0.5 bg-red-100 text-red-700 text-xs rounded-full font-medium">
{discountPercentage}% OFF
</span>
</>
)}
</div>
);
}
interface PriceRangeDisplayProps {
minPrice: number;
maxPrice: number;
currency?: string;
}
export function PriceRangeDisplay({
minPrice,
maxPrice,
currency = 'USD',
}: PriceRangeDisplayProps) {
const formatPrice = (value: number) => {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currency,
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}).format(value);
};
if (minPrice === maxPrice) {
return (
<span className="font-semibold text-green-600">
{formatPrice(minPrice)}
</span>
);
}
return (
<span className="font-semibold text-green-600">
{formatPrice(minPrice)} - {formatPrice(maxPrice)}
</span>
);
}
export default PriceDisplay;