refactor: Refatorando estilo da Essay Analysis

This commit is contained in:
Lucas Santana 2025-02-07 10:43:40 -03:00
parent ccbac66d28
commit 8b45fe72e7
2 changed files with 197 additions and 138 deletions

View File

@ -12,13 +12,13 @@ const Progress = React.forwardRef<
<ProgressPrimitive.Root <ProgressPrimitive.Root
ref={ref} ref={ref}
className={cn( className={cn(
"relative h-4 w-full overflow-hidden rounded-full bg-secondary", "relative h-4 w-full overflow-hidden rounded-full bg-gray-200",
className className
)} )}
{...props} {...props}
> >
<ProgressPrimitive.Indicator <ProgressPrimitive.Indicator
className="h-full w-full flex-1 bg-primary transition-all" className="h-full w-full flex-1 bg-purple-600 transition-all"
style={{ transform: `translateX(-${100 - (value || 0)}%)` }} style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/> />
</ProgressPrimitive.Root> </ProgressPrimitive.Root>

View File

@ -40,6 +40,32 @@ interface Essay {
}; };
} }
interface EssayAnalysisData {
id: string;
essay_id: string;
overall_score: number;
suggestions: string;
created_at: string;
feedback: Array<{
structure_feedback: string;
content_feedback: string;
language_feedback: string;
}>;
strengths: Array<{
strength: string;
}>;
improvements: Array<{
improvement: string;
}>;
scores: Array<{
adequacy: number;
coherence: number;
cohesion: number;
vocabulary: number;
grammar: number;
}>;
}
export function EssayAnalysis() { export function EssayAnalysis() {
const navigate = useNavigate(); const navigate = useNavigate();
const { id } = useParams(); const { id } = useParams();
@ -70,16 +96,57 @@ export function EssayAnalysis() {
setEssay(essayData); setEssay(essayData);
// Carregar análise // Carregar análise
const { data: analysisData, error: analysisError } = await supabase const { data, error: analysisError } = await supabase
.from('essay_analyses') .from('essay_analyses')
.select('*') .select(`
*,
feedback:essay_analysis_feedback(
structure_feedback,
content_feedback,
language_feedback
),
strengths:essay_analysis_strengths(
strength
),
improvements:essay_analysis_improvements(
improvement
),
scores:essay_analysis_scores(
adequacy,
coherence,
cohesion,
vocabulary,
grammar
)
`)
.eq('essay_id', id) .eq('essay_id', id)
.order('created_at', { ascending: false }) .order('created_at', { ascending: false })
.limit(1) .limit(1)
.single(); .single();
if (analysisError) throw analysisError; if (analysisError) throw analysisError;
setAnalysis(analysisData);
// Transformar os dados para o formato esperado
const analysisData = data as EssayAnalysisData;
const analysis: EssayAnalysis = {
...analysisData,
feedback: {
structure: analysisData.feedback[0]?.structure_feedback || '',
content: analysisData.feedback[0]?.content_feedback || '',
language: analysisData.feedback[0]?.language_feedback || ''
},
strengths: analysisData.strengths?.map((s: { strength: string }) => s.strength) || [],
improvements: analysisData.improvements?.map((i: { improvement: string }) => i.improvement) || [],
criteria_scores: {
adequacy: analysisData.scores[0]?.adequacy || 0,
coherence: analysisData.scores[0]?.coherence || 0,
cohesion: analysisData.scores[0]?.cohesion || 0,
vocabulary: analysisData.scores[0]?.vocabulary || 0,
grammar: analysisData.scores[0]?.grammar || 0
}
};
setAnalysis(analysis);
} catch (error) { } catch (error) {
console.error('Erro ao carregar dados:', error); console.error('Erro ao carregar dados:', error);
} finally { } finally {
@ -96,155 +163,147 @@ export function EssayAnalysis() {
<Button <Button
variant="ghost" variant="ghost"
onClick={() => navigate('/aluno/redacoes')} onClick={() => navigate('/aluno/redacoes')}
className="text-purple-600 hover:text-purple-700" className="flex items-center gap-2 text-gray-600 hover:text-gray-900"
trackingId="essay-analysis-back-to-list-button" trackingId="essay-analysis-back-to-list-button"
> >
<ArrowLeft className="mr-2 h-4 w-4" /> <ArrowLeft className="h-5 w-5" />
Voltar para lista de redações Voltar para redações
</Button> </Button>
<Button </div>
variant="ghost"
onClick={() => navigate(`/aluno/redacoes/${id}`)} <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6 space-y-6">
className="text-gray-600 hover:text-gray-900" {/* Título e Tipo */}
trackingId="essay-analysis-back-to-essay-button" <div className="border-b border-gray-200 pb-6">
> <h1 className="text-2xl font-bold text-gray-900">{essay.title}</h1>
<ArrowLeft className="mr-2 h-4 w-4" /> <p className="text-gray-500 mt-1">
Voltar para redação
</Button>
<div>
<h1 className="text-3xl font-bold">{essay.title}</h1>
<p className="text-muted-foreground">
{essay.essay_type.title} {essay.essay_genre.title} {essay.essay_type.title} {essay.essay_genre.title}
</p> </p>
</div> </div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6"> {/* Grid de Cards */}
{/* Pontuação Geral */} <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<Card> {/* Pontuação Geral */}
<CardHeader> <Card className="bg-purple-50 border-purple-100">
<CardTitle>Pontuação Geral</CardTitle> <CardContent className="pt-6">
</CardHeader> <div className="flex items-center justify-center">
<CardContent> <div className="text-6xl font-bold text-purple-600">{analysis.overall_score}</div>
<div className="flex items-center justify-center"> <div className="text-2xl text-purple-600 ml-2">/100</div>
<div className="text-6xl font-bold text-primary">
{analysis.overall_score}
</div> </div>
<div className="text-2xl ml-1">/100</div> <p className="text-center text-gray-600 mt-2">Pontuação Geral</p>
</div> </CardContent>
</CardContent> </Card>
</Card>
{/* Pontos Fortes */} {/* Pontos Fortes */}
<Card> <Card className="bg-green-50 border-green-100">
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-2"> <CardTitle className="flex items-center gap-2 text-green-600">
<CheckCircle2 className="h-5 w-5 text-success" /> <CheckCircle2 className="h-5 w-5" />
Pontos Fortes Pontos Fortes
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<ul className="list-disc list-inside space-y-2"> <ul className="list-disc list-inside space-y-2">
{analysis.strengths.map((strength, index) => ( {analysis.strengths.map((strength, index) => (
<li key={index} className="text-success">{strength}</li> <li key={index} className="text-green-600">{strength}</li>
))} ))}
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
{/* Pontos a Melhorar */} {/* Pontos a Melhorar */}
<Card> <Card className="bg-orange-50 border-orange-100">
<CardHeader> <CardHeader>
<CardTitle className="flex items-center gap-2"> <CardTitle className="flex items-center gap-2 text-orange-600">
<XCircle className="h-5 w-5 text-destructive" /> <XCircle className="h-5 w-5" />
Pontos a Melhorar Pontos a Melhorar
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<ul className="list-disc list-inside space-y-2"> <ul className="list-disc list-inside space-y-2">
{analysis.improvements.map((improvement, index) => ( {analysis.improvements.map((improvement, index) => (
<li key={index} className="text-destructive">{improvement}</li> <li key={index} className="text-orange-600">{improvement}</li>
))} ))}
</ul> </ul>
</CardContent> </CardContent>
</Card> </Card>
{/* Feedback Detalhado */} {/* Feedback Detalhado */}
<Card className="md:col-span-2"> <Card className="md:col-span-2 border-gray-200">
<CardHeader> <CardHeader className="border-b border-gray-200">
<CardTitle>Feedback Detalhado</CardTitle> <CardTitle>Feedback Detalhado</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4 pt-4">
<div> <div>
<h4 className="font-semibold mb-2">Estrutura</h4> <h4 className="font-semibold mb-2 text-gray-900">Estrutura</h4>
<p className="text-muted-foreground">{analysis.feedback.structure}</p> <p className="text-gray-600">{analysis.feedback.structure}</p>
</div> </div>
<div> <div>
<h4 className="font-semibold mb-2">Conteúdo</h4> <h4 className="font-semibold mb-2 text-gray-900">Conteúdo</h4>
<p className="text-muted-foreground">{analysis.feedback.content}</p> <p className="text-gray-600">{analysis.feedback.content}</p>
</div> </div>
<div> <div>
<h4 className="font-semibold mb-2">Linguagem</h4> <h4 className="font-semibold mb-2 text-gray-900">Linguagem</h4>
<p className="text-muted-foreground">{analysis.feedback.language}</p> <p className="text-gray-600">{analysis.feedback.language}</p>
</div> </div>
</CardContent> </CardContent>
</Card> </Card>
{/* Critérios de Avaliação */} {/* Critérios de Avaliação */}
<Card> <Card className="border-gray-200">
<CardHeader> <CardHeader className="border-b border-gray-200">
<CardTitle>Critérios de Avaliação</CardTitle> <CardTitle>Critérios de Avaliação</CardTitle>
</CardHeader> </CardHeader>
<CardContent className="space-y-4"> <CardContent className="space-y-4 pt-4">
<div> <div>
<div className="flex justify-between mb-1"> <div className="flex justify-between mb-1">
<span>Adequação ao Gênero</span> <span className="text-gray-600">Adequação ao Gênero</span>
<span>{analysis.criteria_scores.adequacy}%</span> <span className="font-medium">{analysis.criteria_scores.adequacy}%</span>
</div>
<Progress value={analysis.criteria_scores.adequacy} className="h-2" />
</div> </div>
<Progress value={analysis.criteria_scores.adequacy} /> <div>
</div> <div className="flex justify-between mb-1">
<div> <span className="text-gray-600">Coerência</span>
<div className="flex justify-between mb-1"> <span className="font-medium">{analysis.criteria_scores.coherence}%</span>
<span>Coerência</span> </div>
<span>{analysis.criteria_scores.coherence}%</span> <Progress value={analysis.criteria_scores.coherence} className="h-2" />
</div> </div>
<Progress value={analysis.criteria_scores.coherence} /> <div>
</div> <div className="flex justify-between mb-1">
<div> <span className="text-gray-600">Coesão</span>
<div className="flex justify-between mb-1"> <span className="font-medium">{analysis.criteria_scores.cohesion}%</span>
<span>Coesão</span> </div>
<span>{analysis.criteria_scores.cohesion}%</span> <Progress value={analysis.criteria_scores.cohesion} className="h-2" />
</div> </div>
<Progress value={analysis.criteria_scores.cohesion} /> <div>
</div> <div className="flex justify-between mb-1">
<div> <span className="text-gray-600">Vocabulário</span>
<div className="flex justify-between mb-1"> <span className="font-medium">{analysis.criteria_scores.vocabulary}%</span>
<span>Vocabulário</span> </div>
<span>{analysis.criteria_scores.vocabulary}%</span> <Progress value={analysis.criteria_scores.vocabulary} className="h-2" />
</div> </div>
<Progress value={analysis.criteria_scores.vocabulary} /> <div>
</div> <div className="flex justify-between mb-1">
<div> <span className="text-gray-600">Gramática</span>
<div className="flex justify-between mb-1"> <span className="font-medium">{analysis.criteria_scores.grammar}%</span>
<span>Gramática</span> </div>
<span>{analysis.criteria_scores.grammar}%</span> <Progress value={analysis.criteria_scores.grammar} className="h-2" />
</div> </div>
<Progress value={analysis.criteria_scores.grammar} /> </CardContent>
</div> </Card>
</CardContent>
</Card>
{/* Sugestões */} {/* Sugestões */}
<Card className="md:col-span-3"> <Card className="md:col-span-3 bg-blue-50 border-blue-100">
<CardHeader> <CardHeader>
<CardTitle>Sugestões para Melhoria</CardTitle> <CardTitle className="text-blue-600">Sugestões para Melhoria</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<p className="text-muted-foreground whitespace-pre-line"> <p className="text-gray-600 whitespace-pre-line">
{analysis.suggestions} {analysis.suggestions}
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
</div>
</div> </div>
</div> </div>
); );