mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-17 22:07:52 +00:00
Some checks are pending
Docker Build and Push / build (push) Waiting to run
- Corrige tipo de retorno em useExerciseWords - Ajusta usePhonicsExercises para filtrar por categoria - Atualiza queries para usar inner join e ordenação - Adiciona interfaces para melhor tipagem - Corrige convenção de nomes para snake_case
113 lines
4.1 KiB
TypeScript
113 lines
4.1 KiB
TypeScript
import { usePhonicsProgress } from "@/hooks/phonics/usePhonicsProgress";
|
|
import { usePhonicsExercises } from "@/hooks/phonics/usePhonicsExercises";
|
|
import { useAuth } from "@/hooks/useAuth";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Progress } from "@/components/ui/progress";
|
|
import { Star, Trophy } from "lucide-react";
|
|
|
|
export function PhonicsProgressPage() {
|
|
const { user } = useAuth();
|
|
const { data: progress } = usePhonicsProgress(user?.id || "");
|
|
const { data: exercises } = usePhonicsExercises();
|
|
|
|
if (!user || !progress || !exercises) return null;
|
|
|
|
const totalExercises = exercises.length;
|
|
const completedExercises = progress.filter(p => p.completed).length;
|
|
const totalStars = progress.reduce((acc, p) => acc + p.stars, 0);
|
|
const totalXP = progress.reduce((acc, p) => acc + p.xp_earned, 0);
|
|
const completionRate = (completedExercises / totalExercises) * 100;
|
|
|
|
return (
|
|
<div className="container py-6 space-y-8">
|
|
<div className="space-y-2">
|
|
<h1 className="text-2xl font-bold">Seu Progresso</h1>
|
|
<p className="text-muted-foreground">
|
|
Acompanhe seu desenvolvimento nos exercícios fônicos
|
|
</p>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-lg">Exercícios Completados</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-2">
|
|
<div className="text-3xl font-bold">
|
|
{completedExercises} / {totalExercises}
|
|
</div>
|
|
<Progress value={completionRate} className="h-2" />
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-lg">Estrelas Conquistadas</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center gap-2">
|
|
<Star className="w-8 h-8 text-yellow-400 fill-yellow-400" />
|
|
<span className="text-3xl font-bold">{totalStars}</span>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-lg">XP Total</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="flex items-center gap-2">
|
|
<Trophy className="w-8 h-8 text-purple-500" />
|
|
<span className="text-3xl font-bold">{totalXP}</span>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Histórico de Exercícios</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-4">
|
|
{exercises.map((exercise) => {
|
|
const exerciseProgress = progress.find(p => p.exercise_id === exercise.id);
|
|
const progressValue = exerciseProgress ? exerciseProgress.best_score * 100 : 0;
|
|
|
|
return (
|
|
<div key={exercise.id} className="flex items-center gap-4">
|
|
<div className="flex-1">
|
|
<div className="font-medium">{exercise.title}</div>
|
|
<div className="text-sm text-muted-foreground">
|
|
{exerciseProgress?.completed ? "Completo" : "Pendente"}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2">
|
|
{Array.from({ length: 3 }).map((_, i) => (
|
|
<Star
|
|
key={i}
|
|
className={`w-4 h-4 ${
|
|
i < (exerciseProgress?.stars || 0)
|
|
? "text-yellow-400 fill-yellow-400"
|
|
: "text-gray-300"
|
|
}`}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
<div className="w-32">
|
|
<Progress value={progressValue} className="h-2" />
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|