79 lines
3.0 KiB
TypeScript
79 lines
3.0 KiB
TypeScript
"use client";
|
|
|
|
interface BadgeCardProps {
|
|
badge: {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
icon: string;
|
|
earnedDate?: string;
|
|
progress?: number;
|
|
requirement?: number;
|
|
};
|
|
earned: boolean;
|
|
}
|
|
|
|
export default function BadgeCard({ badge, earned }: BadgeCardProps) {
|
|
const progressPercent = badge.progress && badge.requirement
|
|
? (badge.progress / badge.requirement) * 100
|
|
: 0;
|
|
|
|
return (
|
|
<div className={`bg-gray-800 border-2 rounded-xl p-6 transition ${
|
|
earned
|
|
? "border-yellow-500 shadow-lg shadow-yellow-500/20"
|
|
: "border-gray-700 opacity-75"
|
|
}`}>
|
|
<div className="flex flex-col items-center text-center">
|
|
<div className={`w-24 h-24 rounded-full flex items-center justify-center mb-4 transition ${
|
|
earned
|
|
? "bg-gradient-to-br from-yellow-400 to-orange-500 shadow-xl shadow-yellow-500/50 animate-pulse"
|
|
: "bg-gray-700"
|
|
}`}>
|
|
<span className="text-4xl">{badge.icon}</span>
|
|
</div>
|
|
|
|
<h3 className={`text-xl font-bold mb-2 ${earned ? "text-white" : "text-gray-400"}`}>
|
|
{badge.name}
|
|
</h3>
|
|
|
|
<p className="text-gray-400 text-sm mb-4">{badge.description}</p>
|
|
|
|
{earned && badge.earnedDate ? (
|
|
<div className="flex items-center gap-2 bg-yellow-500/20 border border-yellow-500/30 rounded-full px-4 py-2">
|
|
<svg className="w-4 h-4 text-yellow-400" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
|
|
</svg>
|
|
<span className="text-yellow-400 text-sm font-medium">
|
|
Earned {new Date(badge.earnedDate).toLocaleDateString()}
|
|
</span>
|
|
</div>
|
|
) : badge.progress !== undefined && badge.requirement !== undefined ? (
|
|
<div className="w-full">
|
|
<div className="flex justify-between text-xs text-gray-400 mb-2">
|
|
<span>Progress</span>
|
|
<span>{badge.progress} / {badge.requirement}</span>
|
|
</div>
|
|
<div className="w-full bg-gray-700 rounded-full h-2 overflow-hidden">
|
|
<div
|
|
className="bg-gradient-to-r from-yellow-500 to-orange-500 h-full rounded-full transition-all duration-500"
|
|
style={{ width: `${progressPercent}%` }}
|
|
></div>
|
|
</div>
|
|
<p className="text-xs text-gray-500 mt-2">
|
|
{Math.round(progressPercent)}% complete
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<div className="flex items-center gap-2 text-gray-500 text-sm">
|
|
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fillRule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clipRule="evenodd" />
|
|
</svg>
|
|
<span>Not earned yet</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|