All checks were successful
CI/CD — Build & Deploy / Build & Deploy (push) Successful in 18s
91 lines
3.2 KiB
TypeScript
91 lines
3.2 KiB
TypeScript
// MilestonesPanel.tsx — Paliers de prestige (Sprint 3)
|
|
// Progress bar vers le prochain milestone, claim button, preview reward
|
|
|
|
import { useGameStore } from "../store/useGameStore";
|
|
import { getClaimableMilestones, getNextMilestone } from "../core/economy";
|
|
import { PRESTIGE_MILESTONES } from "../data/prestigeMilestones";
|
|
|
|
export function MilestonesPanel() {
|
|
const state = useGameStore((s) => s.state);
|
|
const claim = useGameStore((s) => s.claimMilestone);
|
|
|
|
if (state.prestigeCount < 1) return null;
|
|
|
|
const claimable = getClaimableMilestones(state);
|
|
const nextMilestone = getNextMilestone(state);
|
|
const claimed = state.claimedMilestones ?? [];
|
|
const totalClaimed = claimed.length;
|
|
|
|
return (
|
|
<div className="gp">
|
|
<div className="flex justify-between items-center">
|
|
<span className="gp-title">Milestones</span>
|
|
<span className="gp-label">{totalClaimed}/{PRESTIGE_MILESTONES.length}</span>
|
|
</div>
|
|
|
|
{/* Claimable milestones */}
|
|
{claimable.length > 0 && (
|
|
<div className="flex flex-col gap-1.5">
|
|
{claimable.map((m) => (
|
|
<div key={m.id} className="gp-row gp-row--evolution border-purple-400/30!">
|
|
<div className="flex flex-col min-w-0">
|
|
<span className="gp-value text-[0.7rem]!">{m.name}</span>
|
|
<span className="gp-label">{m.reward.label}</span>
|
|
</div>
|
|
<button
|
|
onClick={() => claim(m.id)}
|
|
className="gp-btn gp-btn--buy"
|
|
>
|
|
Claim
|
|
</button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{/* Progress vers le prochain milestone */}
|
|
{nextMilestone && (
|
|
<div className="flex flex-col gap-1">
|
|
<div className="flex justify-between">
|
|
<span className="gp-label">Prochain : {nextMilestone.name}</span>
|
|
<span className="gp-label">
|
|
{state.prestigeCount}/{nextMilestone.threshold}
|
|
</span>
|
|
</div>
|
|
<div className="gp-progress">
|
|
<div
|
|
className="gp-progress-fill bg-gradient-to-r from-purple-600 to-purple-400"
|
|
style={{
|
|
width: `${Math.min((state.prestigeCount / nextMilestone.threshold) * 100, 100).toFixed(1)}%`,
|
|
}}
|
|
/>
|
|
</div>
|
|
<span className="gp-label">{nextMilestone.reward.label}</span>
|
|
</div>
|
|
)}
|
|
|
|
{/* Tous les milestones réclamés */}
|
|
{!nextMilestone && claimable.length === 0 && (
|
|
<span className="gp-label text-center gp-accent-purple">
|
|
Tous les milestones reclames !
|
|
</span>
|
|
)}
|
|
|
|
{/* Liste compacte des milestones passés */}
|
|
{totalClaimed > 0 && claimable.length === 0 && (
|
|
<div className="flex flex-wrap gap-1 mt-1">
|
|
{PRESTIGE_MILESTONES.filter((m) => claimed.includes(m.id)).map((m) => (
|
|
<span
|
|
key={m.id}
|
|
className="gp-label text-[0.55rem]! px-1.5 py-0.5 rounded bg-purple-500/10 border border-purple-500/20"
|
|
title={`${m.name} — ${m.description}`}
|
|
>
|
|
{m.threshold}
|
|
</span>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|