54 lines
2.1 KiB
JavaScript
54 lines
2.1 KiB
JavaScript
import React from 'react'
|
|
import AchievementBadge from './AchievementBadge'
|
|
|
|
function cx(...parts) {
|
|
return parts.filter(Boolean).join(' ')
|
|
}
|
|
|
|
export default function AchievementCard({ achievement, className = '' }) {
|
|
const unlocked = Boolean(achievement?.unlocked)
|
|
const progress = Number(achievement?.progress || 0)
|
|
const target = Number(achievement?.condition_value || 0)
|
|
const percent = Math.max(0, Math.min(100, Number(achievement?.progress_percent || 0)))
|
|
|
|
return (
|
|
<article
|
|
className={cx(
|
|
'rounded-2xl border p-4 shadow-lg transition',
|
|
unlocked
|
|
? 'border-emerald-400/25 bg-[linear-gradient(180deg,rgba(16,185,129,0.08),rgba(15,23,42,0.72))]'
|
|
: 'border-white/10 bg-white/[0.04]',
|
|
className,
|
|
)}
|
|
>
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div className="min-w-0">
|
|
<AchievementBadge achievement={achievement} compact />
|
|
<h3 className="mt-3 text-base font-semibold text-white">{achievement?.name}</h3>
|
|
<p className="mt-1 text-sm text-slate-300">{achievement?.description}</p>
|
|
</div>
|
|
<div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl border border-white/10 bg-white/5 text-lg text-white/90">
|
|
<i className={`fa-solid ${achievement?.icon || 'fa-trophy'}`} />
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-4 flex items-center justify-between gap-3 text-xs text-slate-400">
|
|
<span>{achievement?.xp_reward || 0} XP reward</span>
|
|
{unlocked ? <span>Unlocked</span> : <span>{progress} / {target}</span>}
|
|
</div>
|
|
|
|
<div className="mt-2 h-2 overflow-hidden rounded-full bg-white/10 ring-1 ring-white/10">
|
|
<div
|
|
className={cx('h-full rounded-full transition-[width] duration-500', unlocked ? 'bg-emerald-400' : 'bg-sky-400')}
|
|
style={{ width: `${unlocked ? 100 : percent}%` }}
|
|
/>
|
|
</div>
|
|
|
|
{achievement?.unlocked_at ? (
|
|
<p className="mt-3 text-xs text-slate-500">
|
|
Unlocked {new Date(achievement.unlocked_at).toLocaleDateString()}
|
|
</p>
|
|
) : null}
|
|
</article>
|
|
)
|
|
} |