All files / client/src/pages achievements.tsx

0% Statements 0/16
0% Branches 0/12
0% Functions 0/6
0% Lines 0/13

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140                                                                                                                                                                                                                                                                                       
import { useQuery } from "@tanstack/react-query";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Trophy, Target, Flame, Star, Award, Zap } from "lucide-react";
import { Skeleton } from "@/components/ui/skeleton";
import type { Resolution, CheckIn } from "@shared/schema";
 
interface Achievement {
  id: string;
  title: string;
  description: string;
  icon: React.ReactNode;
  unlocked: boolean;
  unlockedAt?: string;
}
 
export function Achievements() {
  const { data: resolutions = [], isLoading: resolutionsLoading } = useQuery<Resolution[]>({
    queryKey: ["/api/resolutions"],
  });
 
  const { data: checkIns = [], isLoading: checkInsLoading } = useQuery<CheckIn[]>({
    queryKey: ["/api/check-ins"],
  });
 
  const isLoading = resolutionsLoading || checkInsLoading;
 
  const completedCount = resolutions.filter((r) => r.status === "completed").length;
  const inProgressCount = resolutions.filter((r) => r.status === "in_progress").length;
  const totalCheckIns = checkIns.length;
 
  const achievements: Achievement[] = [
    {
      id: "first-resolution",
      title: "Getting Started",
      description: "Create your first resolution",
      icon: <Target className="h-6 w-6" />,
      unlocked: resolutions.length >= 1,
    },
    {
      id: "five-resolutions",
      title: "Ambitious",
      description: "Create 5 resolutions",
      icon: <Star className="h-6 w-6" />,
      unlocked: resolutions.length >= 5,
    },
    {
      id: "first-complete",
      title: "First Victory",
      description: "Complete your first resolution",
      icon: <Trophy className="h-6 w-6" />,
      unlocked: completedCount >= 1,
    },
    {
      id: "three-complete",
      title: "Hat Trick",
      description: "Complete 3 resolutions",
      icon: <Award className="h-6 w-6" />,
      unlocked: completedCount >= 3,
    },
    {
      id: "first-checkin",
      title: "Check In",
      description: "Log your first progress check-in",
      icon: <Flame className="h-6 w-6" />,
      unlocked: totalCheckIns >= 1,
    },
    {
      id: "ten-checkins",
      title: "Consistent",
      description: "Log 10 progress check-ins",
      icon: <Zap className="h-6 w-6" />,
      unlocked: totalCheckIns >= 10,
    },
  ];
 
  const unlockedCount = achievements.filter((a) => a.unlocked).length;
 
  if (isLoading) {
    return (
      <div className="p-6 space-y-6">
        <Skeleton className="h-9 w-48" />
        <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
          {[1, 2, 3, 4, 5, 6].map((i) => (
            <Skeleton key={i} className="h-40" />
          ))}
        </div>
      </div>
    );
  }
 
  return (
    <div className="p-6 space-y-6">
      <div>
        <h1 className="text-3xl font-semibold" data-testid="text-achievements-title">
          Achievements
        </h1>
        <p className="text-muted-foreground mt-1">
          {unlockedCount} of {achievements.length} achievements unlocked
        </p>
      </div>
 
      <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
        {achievements.map((achievement) => (
          <Card
            key={achievement.id}
            className={`border-card-border transition-all ${
              achievement.unlocked 
                ? "bg-card" 
                : "opacity-50 grayscale"
            }`}
            data-testid={`card-achievement-${achievement.id}`}
          >
            <CardHeader className="pb-3">
              <div className="flex items-center justify-between gap-2">
                <div className={`p-3 rounded-md ${
                  achievement.unlocked 
                    ? "bg-primary/10 text-primary" 
                    : "bg-muted text-muted-foreground"
                }`}>
                  {achievement.icon}
                </div>
                {achievement.unlocked && (
                  <Badge className="bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-400 border-0">
                    Unlocked
                  </Badge>
                )}
              </div>
            </CardHeader>
            <CardContent>
              <CardTitle className="text-lg mb-1">{achievement.title}</CardTitle>
              <p className="text-sm text-muted-foreground">{achievement.description}</p>
            </CardContent>
          </Card>
        ))}
      </div>
    </div>
  );
}