Untitled
unknown
plain_text
a year ago
4.5 kB
6
Indexable
import { useState } from 'react';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { Progress } from '@/components/ui/progress';
import { Switch } from '@/components/ui/switch';
import { Badge } from '@/components/ui/badge';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import * as icons from 'lucide-react';
import achievementsData from '@/data/achievements.json';
import './App.css';
type Achievement = {
id: string;
title: string;
description: string;
progress: number;
target: number;
completed: boolean;
icon: keyof typeof icons;
category: string;
archived: boolean;
};
function App() {
const [showArchived, setShowArchived] = useState(false);
const achievements = achievementsData.achievements as Achievement[];
const categories = [...new Set(achievements.map((a) =>
a.category.charAt(0).toUpperCase() + a.category.slice(1)
))];
const filteredAchievements = achievements.filter(
(achievement) => achievement.archived === showArchived
);
return (
<div className="min-h-screen bg-background p-8">
<div className="max-w-4xl mx-auto space-y-8">
<div className="flex items-center justify-between">
<div>
<h1 className="text-4xl font-bold text-foreground mb-2">EcoBot Achievements</h1>
<p className="text-muted-foreground">Track your recycling journey</p>
</div>
<div className="flex items-center space-x-2">
<span className="text-sm text-muted-foreground">Show Archived</span>
<Switch
checked={showArchived}
onCheckedChange={setShowArchived}
/>
</div>
</div>
<Tabs defaultValue={categories[0].toLowerCase()} className="space-y-4">
<TabsList>
{categories.map((category) => (
<TabsTrigger
key={category}
value={category.toLowerCase()}
className="capitalize"
>
{category}
</TabsTrigger>
))}
</TabsList>
{categories.map((category) => (
<TabsContent
key={category}
value={category.toLowerCase()}
className="grid gap-6 md:grid-cols-2"
>
{filteredAchievements
.filter((a) => a.category === category.toLowerCase())
.map((achievement) => {
const Icon = icons[achievement.icon];
return (
<Card key={achievement.id}>
<CardHeader className="flex flex-row items-center gap-4">
<div className="p-2 bg-primary/10 rounded-lg">
{Icon && <Icon className="h-6 w-6 text-primary" />}
</div>
<div className="flex-1">
<CardTitle className="flex items-center gap-2">
{achievement.title}
{achievement.completed && (
<Badge variant="default" className="bg-green-600">
Completed
</Badge>
)}
</CardTitle>
<CardDescription>{achievement.description}</CardDescription>
</div>
</CardHeader>
<CardContent>
<div className="flex items-center justify-between mb-2">
<span className="text-sm text-muted-foreground">
Progress: {achievement.progress}/{achievement.target}
</span>
<span className="text-sm text-muted-foreground">
{Math.round((achievement.progress / achievement.target) * 100)}%
</span>
</div>
<Progress
value={(achievement.progress / achievement.target) * 100}
className="h-2"
/>
</CardContent>
</Card>
);
})}
</TabsContent>
))}
</Tabs>
</div>
</div>
);
}
export default App;Editor is loading...
Leave a Comment