'use client'; import { useState } from 'react'; import { GameCard } from '@/components/ui/game-card'; import { Badge } from '@/components/ui/badge'; import { ActionButton } from '@/components/ui/action-button'; import { ScrollArea } from '@/components/ui/scroll-area'; import { ManaBar } from '@/components/ui/mana-bar'; import { Trophy, Lock, CheckCircle, ChevronDown, ChevronUp } from 'lucide-react'; import type { AchievementState } from '@/lib/game/types'; import { ACHIEVEMENTS, getAchievementsByCategory, isAchievementRevealed } from '@/lib/game/data/achievements'; import { GameState } from '@/lib/game/types'; // Map achievement categories to CSS variables for colors const CATEGORY_COLOR_MAP: Record = { combat: 'var(--color-danger)', progression: 'var(--rarity-legendary)', crafting: 'var(--mana-dark)', magic: 'var(--mana-water)', special: 'var(--mana-stellar)', }; interface AchievementsProps { achievements: AchievementState; gameState: Pick; } export function AchievementsDisplay({ achievements, gameState }: AchievementsProps) { const [expandedCategory, setExpandedCategory] = useState('combat'); const categories = getAchievementsByCategory(); const unlockedCount = achievements.unlocked.length; const totalCount = Object.keys(ACHIEVEMENTS).length; // Calculate progress for each achievement const getProgress = (achievementId: string): number => { const achievement = ACHIEVEMENTS[achievementId]; if (!achievement) return 0; if (achievements.unlocked.includes(achievementId)) return achievement.requirement.value; const { type, subType } = achievement.requirement; switch (type) { case 'floor': if (subType === 'noPacts') { return gameState.maxFloorReached >= achievement.requirement.value && gameState.signedPacts.length === 0 ? achievement.requirement.value : gameState.maxFloorReached; } return gameState.maxFloorReached; case 'spells': return gameState.totalSpellsCast || 0; case 'damage': return gameState.totalDamageDealt || 0; case 'mana': return gameState.totalManaGathered || 0; case 'pact': return gameState.signedPacts.length; case 'craft': return gameState.totalCraftsCompleted || 0; default: return achievements.progress[achievementId] || 0; } }; return (

Achievements

{unlockedCount} / {totalCount}
{Object.entries(categories).map(([category, categoryAchievements]) => (
setExpandedCategory(expandedCategory === category ? null : category)} aria-expanded={expandedCategory === category} aria-label={`${category} category - ${categoryAchievements.filter(a => achievements.unlocked.includes(a.id)).length} of ${categoryAchievements.length} unlocked`} > {category.charAt(0).toUpperCase() + category.slice(1)} {categoryAchievements.filter(a => achievements.unlocked.includes(a.id)).length} / {categoryAchievements.length} {expandedCategory === category ? ( ) : ( )} {expandedCategory === category && (
{categoryAchievements.map((achievement) => { const isUnlocked = achievements.unlocked.includes(achievement.id); const progress = getProgress(achievement.id); const isRevealed = isAchievementRevealed(achievement, progress); const progressPercent = Math.min(100, (progress / achievement.requirement.value) * 100); if (!isRevealed && !isUnlocked) { return (
); } return (
{isUnlocked ? (
{achievement.reward.title && isUnlocked && ( Title )}
{achievement.desc}
{!isUnlocked && (
{progress.toLocaleString()} / {achievement.requirement.value.toLocaleString()} {progressPercent.toFixed(0)}%
)} {isUnlocked && achievement.reward && (
Reward: {achievement.reward.insight && ` +${achievement.reward.insight} Insight`} {achievement.reward.manaBonus && ` +${achievement.reward.manaBonus} Max Mana`} {achievement.reward.damageBonus && ` +${(achievement.reward.damageBonus * 100).toFixed(0)}% Damage`} {achievement.reward.title && ` "${achievement.reward.title}"`}
)}
); })}
)}
))}
); } AchievementsDisplay.displayName = "AchievementsDisplay";