186 lines
6.5 KiB
TypeScript
186 lines
6.5 KiB
TypeScript
|
|
"use client";
|
|||
|
|
|
|||
|
|
import Image from "next/image";
|
|||
|
|
import { Button } from "@heroui/react";
|
|||
|
|
|
|||
|
|
interface ProductCardProps {
|
|||
|
|
name: string;
|
|||
|
|
category: string;
|
|||
|
|
icon?: string;
|
|||
|
|
yieldAPY: string;
|
|||
|
|
poolCap: string;
|
|||
|
|
maturity: string;
|
|||
|
|
risk: string;
|
|||
|
|
riskLevel: 1 | 2 | 3;
|
|||
|
|
lockUp: string;
|
|||
|
|
circulatingSupply: string;
|
|||
|
|
poolCapacityPercent: number;
|
|||
|
|
onInvest?: () => void;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default function ProductCard({
|
|||
|
|
name,
|
|||
|
|
category,
|
|||
|
|
icon,
|
|||
|
|
yieldAPY,
|
|||
|
|
poolCap,
|
|||
|
|
maturity,
|
|||
|
|
risk,
|
|||
|
|
riskLevel,
|
|||
|
|
lockUp,
|
|||
|
|
circulatingSupply,
|
|||
|
|
poolCapacityPercent,
|
|||
|
|
onInvest,
|
|||
|
|
}: ProductCardProps) {
|
|||
|
|
const getRiskColor = (level: number) => {
|
|||
|
|
switch (level) {
|
|||
|
|
case 1:
|
|||
|
|
return "bg-green-500";
|
|||
|
|
case 2:
|
|||
|
|
return "bg-yellow-500";
|
|||
|
|
case 3:
|
|||
|
|
return "bg-red-500";
|
|||
|
|
default:
|
|||
|
|
return "bg-gray-300";
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const getCategoryColor = (cat: string) => {
|
|||
|
|
if (cat.includes("Quant")) {
|
|||
|
|
return "bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800 text-blue-700 dark:text-blue-300";
|
|||
|
|
} else if (cat.includes("Real Estate")) {
|
|||
|
|
return "bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800 text-green-700 dark:text-green-300";
|
|||
|
|
}
|
|||
|
|
return "bg-bg-subtle dark:bg-gray-700 border-border-normal dark:border-gray-600 text-text-tertiary dark:text-gray-400";
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<div className="bg-bg-surface dark:bg-gray-800 rounded-2xl border border-border-gray dark:border-gray-700 p-6 flex flex-col gap-6 hover:shadow-lg transition-shadow">
|
|||
|
|
{/* Product Header */}
|
|||
|
|
<div className="flex items-start gap-4">
|
|||
|
|
<div className="w-16 h-16 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center flex-shrink-0">
|
|||
|
|
{icon ? (
|
|||
|
|
<Image src={icon} alt={name} width={32} height={32} />
|
|||
|
|
) : (
|
|||
|
|
<span className="text-2xl">🏛️</span>
|
|||
|
|
)}
|
|||
|
|
</div>
|
|||
|
|
<div className="flex flex-col gap-2 flex-1">
|
|||
|
|
<h3 className="text-body-large font-bold text-text-primary dark:text-white leading-tight">
|
|||
|
|
{name}
|
|||
|
|
</h3>
|
|||
|
|
<div
|
|||
|
|
className={`inline-flex self-start px-3 py-1 rounded-full border text-caption-tiny font-medium ${getCategoryColor(
|
|||
|
|
category
|
|||
|
|
)}`}
|
|||
|
|
>
|
|||
|
|
{category}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Product Metrics - Two Columns */}
|
|||
|
|
<div className="grid grid-cols-2 gap-x-8 gap-y-4">
|
|||
|
|
{/* Column 1 */}
|
|||
|
|
<div className="flex flex-col gap-4">
|
|||
|
|
<div className="flex flex-col gap-1">
|
|||
|
|
<span className="text-body-small text-text-tertiary dark:text-gray-400">
|
|||
|
|
Yield APY
|
|||
|
|
</span>
|
|||
|
|
<span className="text-body-large font-bold text-green-600 dark:text-green-400">
|
|||
|
|
{yieldAPY}
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
<div className="flex flex-col gap-1">
|
|||
|
|
<span className="text-body-small text-text-tertiary dark:text-gray-400">
|
|||
|
|
Maturity
|
|||
|
|
</span>
|
|||
|
|
<span className="text-body-default font-medium text-text-primary dark:text-white">
|
|||
|
|
{maturity}
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
<div className="flex flex-col gap-1">
|
|||
|
|
<span className="text-body-small text-text-tertiary dark:text-gray-400">
|
|||
|
|
Lock-Up
|
|||
|
|
</span>
|
|||
|
|
<span className="text-body-default font-medium text-text-primary dark:text-white">
|
|||
|
|
{lockUp}
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Column 2 */}
|
|||
|
|
<div className="flex flex-col gap-4">
|
|||
|
|
<div className="flex flex-col gap-1">
|
|||
|
|
<span className="text-body-small text-text-tertiary dark:text-gray-400">
|
|||
|
|
Pool CaP
|
|||
|
|
</span>
|
|||
|
|
<span className="text-body-large font-bold text-text-primary dark:text-white">
|
|||
|
|
{poolCap}
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
<div className="flex flex-col gap-1">
|
|||
|
|
<span className="text-body-small text-text-tertiary dark:text-gray-400">
|
|||
|
|
Risk
|
|||
|
|
</span>
|
|||
|
|
<div className="flex items-center gap-2">
|
|||
|
|
<span className="text-body-default font-medium text-text-primary dark:text-white">
|
|||
|
|
{risk}
|
|||
|
|
</span>
|
|||
|
|
<div className="flex items-center gap-1">
|
|||
|
|
{[1, 2, 3].map((level) => (
|
|||
|
|
<div
|
|||
|
|
key={level}
|
|||
|
|
className={`w-1.5 h-4 rounded-sm transition-colors ${
|
|||
|
|
level <= riskLevel
|
|||
|
|
? getRiskColor(riskLevel)
|
|||
|
|
: "bg-gray-300 dark:bg-gray-600"
|
|||
|
|
}`}
|
|||
|
|
/>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div className="flex flex-col gap-1">
|
|||
|
|
<span className="text-body-small text-text-tertiary dark:text-gray-400">
|
|||
|
|
Circulating supply
|
|||
|
|
</span>
|
|||
|
|
<span className="text-body-default font-medium text-text-primary dark:text-white">
|
|||
|
|
{circulatingSupply}
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
{/* Divider */}
|
|||
|
|
<div className="border-t border-border-gray dark:border-gray-700" />
|
|||
|
|
|
|||
|
|
{/* Pool Capacity & Invest Button */}
|
|||
|
|
<div className="flex items-end justify-between gap-6">
|
|||
|
|
<div className="flex-1 flex flex-col gap-2">
|
|||
|
|
<div className="flex items-center justify-between">
|
|||
|
|
<span className="text-body-small text-text-tertiary dark:text-gray-400">
|
|||
|
|
Pool Capacity
|
|||
|
|
</span>
|
|||
|
|
<span className="text-body-small font-bold text-text-primary dark:text-white">
|
|||
|
|
{poolCapacityPercent}% Filled
|
|||
|
|
</span>
|
|||
|
|
</div>
|
|||
|
|
<div className="w-full h-2.5 bg-bg-subtle dark:bg-gray-700 rounded-full overflow-hidden">
|
|||
|
|
<div
|
|||
|
|
className="h-full bg-gradient-to-r from-blue-500 to-purple-600 rounded-full transition-all duration-300"
|
|||
|
|
style={{ width: `${poolCapacityPercent}%` }}
|
|||
|
|
/>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<Button
|
|||
|
|
onPress={onInvest}
|
|||
|
|
className="px-8 py-3 bg-text-primary dark:bg-blue-600 text-white font-bold text-body-default rounded-xl h-auto min-w-[120px]"
|
|||
|
|
>
|
|||
|
|
Invest
|
|||
|
|
</Button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
}
|