// ─── Skill Row Component ─────────────────────────────────────────────────── // Individual skill row for the Skills tab - extracted from SkillsTab for modularity 'use client'; import { useState } from 'react'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import { ChevronRight } from 'lucide-react'; import type { SkillUpgradeChoice } from '@/lib/game/types'; import { ELEMENTS } from '@/lib/game/constants'; import { formatStudyTime } from '@/lib/game/formatting'; import { getUpgradesForSkillAtMilestone, getNextTierSkill, getTierMultiplier, SKILL_EVOLUTION_PATHS } from '@/lib/game/skill-evolution'; import type { ComputedEffects } from '@/lib/game/upgrade-effects.types'; import { SPECIAL_EFFECTS, hasSpecial } from '@/lib/game/special-effects'; import { MilestoneProgress } from './MilestoneProgress'; import { SkillMultipliers } from './SkillMultipliers'; type StudyTarget = { type: 'skill' | 'spell'; id: string; progress: number; required: number; } | null; interface SkillRowProps { skillId: string; def: { name: string; desc: string; cat: string; max: number; studyTime: number; base: number; cost?: { type: 'element'; element: string; amount: number } | { type: 'raw'; amount: number }; req?: Record; }; level: number; maxed: boolean; isStudying: boolean; tierMultiplier: number; skillDisplayName: string; selectedUpgrades: string[]; selectedL5: string[]; selectedL10: string[]; prereqMet: boolean; canStudy: boolean; isParallelStudy: boolean; canParallelStudy: boolean; canTierUp: boolean; hasInsufficientMana: boolean; currentStudyTarget: StudyTarget; milestoneInfo: { milestone: 5 | 10; hasUpgrades: boolean; selectedCount: number } | null; upgradeEffects: ComputedEffects; // Costs and times cost: number; additionalCost?: { type: 'element'; element: string; amount: number }; effectiveStudyTime: number; costMult: number; speedMult: number; // Callbacks onStudy: (skillId: string) => void; onParallelStudy: (skillId: string) => void; onCancelStudy: (skillId: string) => void; onUpgradeDialogOpen: (skillId: string, milestone: 5 | 10) => void; onTierUp: (skillId: string) => void; onShowToast: (type: 'info' | 'error', title: string, description: string) => void; tierUpLabel?: string; } export function SkillRow(props: SkillRowProps) { const { skillId, def, level, maxed, isStudying, tierMultiplier, skillDisplayName, selectedUpgrades, selectedL5, selectedL10, prereqMet, canStudy, isParallelStudy, canParallelStudy, canTierUp, hasInsufficientMana, currentStudyTarget, milestoneInfo, upgradeEffects, cost, additionalCost, effectiveStudyTime, costMult, speedMult, onStudy, onParallelStudy, onCancelStudy, onUpgradeDialogOpen, onTierUp, } = props; return (
{skillDisplayName} {level > 0 && Lv.{level}} {selectedUpgrades.length > 0 && (
{selectedL5.length > 0 && ( L5: {selectedL5.length} )} {selectedL10.length > 0 && ( L10: {selectedL10.length} )}
)}
{def.desc}{level > 0 && tierMultiplier !== 1 && ` (Tier ${tierMultiplier}x effect)`}
{!prereqMet && def.req && (
Requires: {Object.entries(def.req).map(([r, rl]) => `${r} Lv.${rl}`).join(', ')}
)} {hasInsufficientMana && (
Insufficient mana! Need {cost} mana to study.
)}
{/* Level dots */}
{Array.from({ length: def.max }).map((_, i) => (
))}
{isStudying ? (
{formatStudyTime(currentStudyTarget?.progress || 0)}/{formatStudyTime(def.studyTime * (level > 1 ? level : 1))}
) : milestoneInfo ? ( ) : canTierUp ? ( ) : maxed ? ( Maxed ) : (
{hasSpecial(upgradeEffects, SPECIAL_EFFECTS.PARALLEL_STUDY) && currentStudyTarget && !isParallelStudy && canParallelStudy && canStudy && (

Study in parallel (50% speed)

)}
)}
); }