Untitled

 avatar
unknown
plain_text
a month ago
7.5 kB
3
Indexable
import React, { useEffect, useState } from 'react';
import { useMetrics } from '@/hooks/useMetrics';
import { AppSidebar } from "@/components/app-sidebar";
import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { Separator } from "@/components/ui/separator";
import {
  SidebarInset,
  SidebarProvider,
  SidebarTrigger,
} from "@/components/ui/sidebar";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Progress } from "@/components/ui/progress";
import { Badge } from "@/components/ui/badge";
import { Trophy, Lock, Unlock, Award, Target, Calendar } from 'lucide-react';
import { useTranslation, type SupportedLanguages } from "@/utils/translations";
import { useSettings } from "@/hooks/useSettings";
import confetti from 'canvas-confetti';

const AchievementsPage = () => {
  const { metrics, loading, error } = useMetrics();
  const { settings } = useSettings();
  const { t } = useTranslation(settings?.language as SupportedLanguages || 'EN');
  const [confettiTriggered, setConfettiTrigered] = useState(false);

  useEffect(() => {
    if (metrics?.achievements && !confettiTriggered) {
      const unlockedAchievements = Object.values(metrics.achievements).filter(
        achievement => achievement.status === 'completed'
      );

      if (unlockedAchievements.length > 0) {
        const container = document.querySelector('.achievements-container');
        if (container) {
          const rect = container.getBoundingClientRect();
          const centerX = rect.left + rect.width / 2;
          const centerY = rect.top + rect.height / 2;

          confetti({
            particleCount: 100,
            spread: 70,
            origin: { 
              x: centerX / window.innerWidth,
              y: centerY / window.innerHeight
            },
            disableForReducedMotion: true
          });
          setConfettiTrigered(true);
        }
      }
    }
  }, [metrics, confettiTriggered]);

  if (loading) return <div className="p-4">Loading achievements...</div>;
  if (error) return <div className="p-4 text-red-500">Error loading achievements</div>;
  if (!metrics) return null;

  const achievements = Object.entries(metrics.achievements);
  const unlockedCount = achievements.filter(([_, a]) => a.status === 'completed').length;
  const totalCount = achievements.length;

  const getAchievementIcon = (achievement) => {
    switch (achievement.tier) {
      case 'bronze': return <Trophy className="w-8 h-8 text-amber-600" />;
      case 'silver': return <Trophy className="w-8 h-8 text-gray-400" />;
      case 'gold': return <Trophy className="w-8 h-8 text-yellow-400" />;
      default: return <Award className="w-8 h-8 text-primary" />;
    }
  };

  return (
    <SidebarProvider>
      <AppSidebar />
      <SidebarInset>
        <header className="flex shrink-0 items-center gap-2 border-b px-4 py-6">
          <SidebarTrigger className="-ml-1" />
          <Separator orientation="vertical" className="mr-2 h-4" />
          <Breadcrumb>
            <BreadcrumbList>
              <BreadcrumbItem>
                <BreadcrumbLink href="/">{t('navigation.home')}</BreadcrumbLink>
              </BreadcrumbItem>
              <BreadcrumbSeparator />
              <BreadcrumbItem>
                <BreadcrumbLink href="/achievements">{t('navigation.achievements')}</BreadcrumbLink>
              </BreadcrumbItem>
            </BreadcrumbList>
          </Breadcrumb>
        </header>

        <main className="p-4">
          <Card className="mb-6">
            <CardHeader>
              <CardTitle className="flex items-center gap-2">
                <Trophy className="w-6 h-6 text-primary" />
                Achievement Progress
              </CardTitle>
            </CardHeader>
            <CardContent>
              <div className="flex items-center gap-4">
                <Progress value={(unlockedCount / totalCount) * 100} className="w-full" />
                <span className="text-sm font-medium">
                  {unlockedCount}/{totalCount}
                </span>
              </div>
            </CardContent>
          </Card>

          <div className="achievements-container grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
            {achievements.sort(([, a], [, b]) => {
              // Sort completed first, then by progress percentage
              if (a.status === 'completed' && b.status !== 'completed') return -1;
              if (a.status !== 'completed' && b.status === 'completed') return 1;
              return (b.progress / b.target) - (a.progress / a.target);
            }).map(([id, achievement]) => (
              <Card 
                key={id}
                className={`relative overflow-hidden ${
                  achievement.status === 'completed' 
                    ? 'border-primary/50 bg-primary/5' 
                    : 'opacity-75'
                }`}
              >
                <CardHeader>
                  <CardTitle className="flex items-center justify-between">
                    <div className="flex items-center gap-2">
                      {getAchievementIcon(achievement)}
                      <span>{achievement.name}</span>
                    </div>
                    {achievement.status === 'completed' ? (
                      <Unlock className="w-5 h-5 text-primary" />
                    ) : (
                      <Lock className="w-5 h-5" />
                    )}
                  </CardTitle>
                </CardHeader>
                <CardContent>
                  <p className="mb-4 text-sm text-muted-foreground">
                    {achievement.description}
                  </p>
                  <div className="space-y-4">
                    <div className="flex items-center gap-2">
                      <Target className="w-4 h-4" />
                      <Progress 
                        value={(achievement.progress / achievement.target) * 100} 
                        className="flex-1"
                      />
                      <span className="text-sm font-medium">
                        {achievement.progress}/{achievement.target}
                      </span>
                    </div>
                    {achievement.unlock_date && (
                      <div className="flex items-center gap-2 text-sm text-muted-foreground">
                        <Calendar className="w-4 h-4" />
                        <span>Unlocked: {new Date(achievement.unlock_date).toLocaleDateString()}</span>
                      </div>
                    )}
                    {achievement.tier && (
                      <Badge variant={
                        achievement.tier === 'gold' ? 'default' :
                        achievement.tier === 'silver' ? 'secondary' :
                        'outline'
                      }>
                        {achievement.tier.charAt(0).toUpperCase() + achievement.tier.slice(1)} Tier
                      </Badge>
                    )}
                  </div>
                </CardContent>
              </Card>
            ))}
          </div>
        </main>
      </SidebarInset>
    </SidebarProvider>
  );
};

export default AchievementsPage;
Editor is loading...
Leave a Comment