aethex-forge/client/components/admin/AdminStaffAchievements.tsx
2025-11-11 02:44:36 +00:00

267 lines
8.1 KiB
TypeScript

import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Progress } from "@/components/ui/progress";
import { Trophy, TrendingUp, Star } from "lucide-react";
import { useState } from "react";
interface Achievement {
id: string;
name: string;
description: string;
icon: string;
progress: number;
target: number;
completed: boolean;
earnedBy: number;
rarity: "common" | "rare" | "epic" | "legendary";
}
export default function AdminStaffAchievements() {
const [filterRarity, setFilterRarity] = useState<string>("all");
const achievements: Achievement[] = [
{
id: "first-step",
name: "First Step",
description: "Complete your first task",
icon: "👣",
progress: 1,
target: 1,
completed: true,
earnedBy: 12,
rarity: "common",
},
{
id: "community-champion",
name: "Community Champion",
description: "Help 10 community members",
icon: "🏆",
progress: 7,
target: 10,
completed: false,
earnedBy: 3,
rarity: "epic",
},
{
id: "code-master",
name: "Code Master",
description: "Contribute 50 code reviews",
icon: "💻",
progress: 25,
target: 50,
completed: false,
earnedBy: 2,
rarity: "legendary",
},
{
id: "documentation-king",
name: "Documentation King",
description: "Write 20 documentation entries",
icon: "📚",
progress: 15,
target: 20,
completed: false,
earnedBy: 4,
rarity: "rare",
},
{
id: "bug-squasher",
name: "Bug Squasher",
description: "Fix 25 reported bugs",
icon: "🐛",
progress: 12,
target: 25,
completed: false,
earnedBy: 5,
rarity: "rare",
},
{
id: "mentor",
name: "Mentor",
description: "Mentor 5 junior developers",
icon: "🎓",
progress: 2,
target: 5,
completed: false,
earnedBy: 1,
rarity: "epic",
},
];
const getRarityColor = (rarity: Achievement["rarity"]) => {
const colors: Record<Achievement["rarity"], string> = {
common: "bg-gray-100 text-gray-900 dark:bg-gray-900/30",
rare: "bg-blue-100 text-blue-900 dark:bg-blue-900/30",
epic: "bg-purple-100 text-purple-900 dark:bg-purple-900/30",
legendary: "bg-yellow-100 text-yellow-900 dark:bg-yellow-900/30",
};
return colors[rarity];
};
const filteredAchievements =
filterRarity === "all"
? achievements
: achievements.filter((a) => a.rarity === filterRarity);
const completedCount = achievements.filter((a) => a.completed).length;
const totalProgress = achievements.reduce((acc, a) => acc + a.progress, 0);
const totalTarget = achievements.reduce((acc, a) => acc + a.target, 0);
return (
<div className="space-y-6">
<div>
<h2 className="text-2xl font-bold mb-2">Achievement Tracking</h2>
<p className="text-muted-foreground">
Team achievements and progress tracking
</p>
</div>
{/* Overview Stats */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground flex items-center gap-2">
<Trophy className="w-4 h-4" />
Completed
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold">{completedCount}</div>
<p className="text-xs text-muted-foreground mt-1">
of {achievements.length} achievements
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground flex items-center gap-2">
<TrendingUp className="w-4 h-4" />
Overall Progress
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold">
{Math.round((totalProgress / totalTarget) * 100)}%
</div>
<Progress
value={(totalProgress / totalTarget) * 100}
className="mt-2"
/>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground flex items-center gap-2">
<Star className="w-4 h-4" />
Team Average
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-3xl font-bold">
{(
achievements.reduce((acc, a) => acc + a.earnedBy, 0) /
achievements.length
).toFixed(1)}
</div>
<p className="text-xs text-muted-foreground mt-1">
members per achievement
</p>
</CardContent>
</Card>
</div>
{/* Filter */}
<div className="flex gap-2">
<button
onClick={() => setFilterRarity("all")}
className={`px-4 py-2 rounded-lg transition ${
filterRarity === "all"
? "bg-blue-100 text-blue-900 dark:bg-blue-900/30"
: "bg-slate-100 dark:bg-slate-800 hover:bg-slate-200 dark:hover:bg-slate-700"
}`}
>
All
</button>
{["common", "rare", "epic", "legendary"].map((rarity) => (
<button
key={rarity}
onClick={() => setFilterRarity(rarity)}
className={`px-4 py-2 rounded-lg transition capitalize ${
filterRarity === rarity
? getRarityColor(rarity as Achievement["rarity"])
: "bg-slate-100 dark:bg-slate-800 hover:bg-slate-200 dark:hover:bg-slate-700"
}`}
>
{rarity}
</button>
))}
</div>
{/* Achievements Grid */}
<div className="grid gap-4 grid-cols-1 md:grid-cols-2">
{filteredAchievements.map((achievement) => (
<Card
key={achievement.id}
className={
achievement.completed
? "border-green-200 dark:border-green-900"
: ""
}
>
<CardHeader className="pb-3">
<div className="flex items-start justify-between">
<div className="flex items-start gap-3">
<div className="text-3xl">{achievement.icon}</div>
<div className="flex-1">
<CardTitle className="text-lg">
{achievement.name}
</CardTitle>
<CardDescription>{achievement.description}</CardDescription>
</div>
</div>
<Badge className={getRarityColor(achievement.rarity)}>
{achievement.rarity}
</Badge>
</div>
</CardHeader>
<CardContent className="space-y-3">
<div>
<div className="flex justify-between text-sm mb-2">
<span>Progress</span>
<span className="font-medium">
{achievement.progress}/{achievement.target}
</span>
</div>
<Progress
value={(achievement.progress / achievement.target) * 100}
/>
</div>
<div className="flex items-center justify-between text-sm text-muted-foreground">
<span>Earned by {achievement.earnedBy} members</span>
{achievement.completed && (
<Badge className="bg-green-100 text-green-900 dark:bg-green-900/30">
Completed
</Badge>
)}
</div>
</CardContent>
</Card>
))}
</div>
{filteredAchievements.length === 0 && (
<Card className="text-center py-8">
<p className="text-muted-foreground">
No achievements with this rarity level
</p>
</Card>
)}
</div>
);
}