diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7d516ea..714a75e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -277,3 +277,20 @@ e este projeto adere ao [Semantic Versioning](https://semver.org/lang/pt-BR/).
- Implementada transformação dos dados para o formato esperado
- Adicionado tratamento para valores nulos
- Melhorada tipagem dos dados retornados
+
+### Modificado
+- Melhorado o fluxo de redações:
+ - Corrigido carregamento do conteúdo da redação após envio para análise
+ - Adicionado salvamento automático do conteúdo antes de enviar para análise
+ - Melhorada visualização do status 'analisada' com badge verde
+ - Adicionado botão "Ver Análise" para redações analisadas
+ - Ajustado Editor para modo somente leitura após envio
+ - Melhorada contagem de palavras em todos os estados da redação
+
+### Técnico
+- Refatorado componente `EssayPage`:
+ - Adicionada lógica de salvamento antes do envio para análise
+ - Melhorada query do Supabase para incluir conteúdo explicitamente
+ - Implementado feedback visual durante operações de salvamento
+ - Otimizado carregamento inicial da redação
+ - Adicionado tratamento de estados para diferentes status da redação
diff --git a/src/pages/student-dashboard/essays/EssayAnalysis.tsx b/src/pages/student-dashboard/essays/EssayAnalysis.tsx
index 8641b64..240bdb2 100644
--- a/src/pages/student-dashboard/essays/EssayAnalysis.tsx
+++ b/src/pages/student-dashboard/essays/EssayAnalysis.tsx
@@ -3,8 +3,9 @@ import { useParams, useNavigate } from 'react-router-dom';
import { supabase } from '@/lib/supabase';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
-import { ArrowLeft, CheckCircle2, XCircle } from 'lucide-react';
+import { ArrowLeft, CheckCircle2, XCircle, Loader2 } from 'lucide-react';
import { Progress } from '@/components/ui/progress';
+import { cn } from '@/lib/utils';
interface EssayAnalysis {
id: string;
@@ -123,155 +124,177 @@ export function EssayAnalysis() {
}
}
- if (loading) return
Carregando...
;
- if (!essay || !analysis) return Análise não encontrada
;
+ if (loading) {
+ return (
+
+
+
+
+
+ {[1, 2, 3].map((i) => (
+
+ ))}
+
+
+
+ );
+ }
+
+ if (!essay || !analysis) {
+ return (
+
+
+
Análise não encontrada
+
navigate('/aluno/redacoes')}
+ className="text-purple-600 hover:text-purple-700"
+ >
+
+ Voltar para redações
+
+
+
+ );
+ }
return (
-
-
navigate(`/aluno/redacoes/${id}`)}
- trackingId="essay-analysis-back-button"
- trackingProperties={{
- action: 'back_to_essay',
- page: 'essay_analysis',
- essay_id: id
- }}
- >
-
- Voltar para redação
-
-
-
{essay.title}
-
- {essay.essay_type.title} • {essay.essay_genre.title}
-
+ {/* Cabeçalho */}
+
+
+
navigate(`/aluno/redacoes/${id}`)}
+ className="text-gray-600 hover:text-gray-900"
+ >
+
+ Voltar para redação
+
+
+
{essay.title}
+
+ {essay.essay_type.title} • {essay.essay_genre.title}
+
+
-
- {/* Pontuação Geral */}
-
-
- Pontuação Geral
-
-
-
-
- {analysis.overall_score}
+ {/* Conteúdo Principal */}
+
+ {/* Cartão de Pontuação */}
+
+
+
+
+ {analysis.overall_score}
+ /100
-
/100
+
Pontuação Geral
- {/* Pontos Fortes */}
-
-
-
-
- Pontos Fortes
-
-
-
-
- {analysis.strengths.map((strength, index) => (
- {strength}
- ))}
-
-
-
+ {/* Grid de Métricas */}
+
+ {/* Pontos Fortes */}
+
+
+
+
+ Pontos Fortes
+
+
+
+
+ {analysis.strengths.map((strength, index) => (
+
+
+ {strength}
+
+ ))}
+
+
+
- {/* Pontos a Melhorar */}
-
-
-
-
- Pontos a Melhorar
-
-
-
-
- {analysis.improvements.map((improvement, index) => (
- {improvement}
+ {/* Pontos a Melhorar */}
+
+
+
+
+ Pontos a Melhorar
+
+
+
+
+ {analysis.improvements.map((improvement, index) => (
+
+
+ {improvement}
+
+ ))}
+
+
+
+
+ {/* Critérios de Avaliação */}
+
+
+ Critérios de Avaliação
+
+
+ {[
+ { label: 'Adequação ao Gênero', value: analysis.criteria_scores.adequacy, color: 'bg-blue-500' },
+ { label: 'Coerência', value: analysis.criteria_scores.coherence, color: 'bg-green-500' },
+ { label: 'Coesão', value: analysis.criteria_scores.cohesion, color: 'bg-purple-500' },
+ { label: 'Vocabulário', value: analysis.criteria_scores.vocabulary, color: 'bg-orange-500' },
+ { label: 'Gramática', value: analysis.criteria_scores.grammar, color: 'bg-pink-500' }
+ ].map((criterion) => (
+
+
+ {criterion.label}
+ {criterion.value}%
+
+
+
))}
-
-
-
+
+
+
{/* Feedback Detalhado */}
-
+
Feedback Detalhado
-
-
-
Estrutura
-
{analysis.feedback.structure}
+
+
+
Estrutura
+
{analysis.feedback.structure}
-
-
Conteúdo
-
{analysis.feedback.content}
+
+
Conteúdo
+
{analysis.feedback.content}
-
-
Linguagem
-
{analysis.feedback.language}
-
-
-
-
- {/* Critérios de Avaliação */}
-
-
- Critérios de Avaliação
-
-
-
-
- Adequação ao Gênero
- {analysis.criteria_scores.adequacy}%
-
-
-
-
-
- Coerência
- {analysis.criteria_scores.coherence}%
-
-
-
-
-
- Coesão
- {analysis.criteria_scores.cohesion}%
-
-
-
-
-
- Vocabulário
- {analysis.criteria_scores.vocabulary}%
-
-
-
-
-
- Gramática
- {analysis.criteria_scores.grammar}%
-
-
+
+
Linguagem
+
{analysis.feedback.language}
{/* Sugestões */}
-
+
- Sugestões para Melhoria
+ Sugestões para Melhoria
-
+
{analysis.suggestions}
@@ -279,4 +302,4 @@ export function EssayAnalysis() {
);
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/pages/student-dashboard/essays/EssayPage.tsx b/src/pages/student-dashboard/essays/EssayPage.tsx
index b35fb18..5f7482d 100644
--- a/src/pages/student-dashboard/essays/EssayPage.tsx
+++ b/src/pages/student-dashboard/essays/EssayPage.tsx
@@ -5,7 +5,7 @@ import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
-import { ArrowLeft, Save, Send, Trash2 } from 'lucide-react';
+import { ArrowLeft, Save, Send, Trash2, BarChart3 } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import {
AlertDialog,
@@ -77,13 +77,20 @@ export function EssayPage() {
.select(`
*,
essay_type:essay_types(*),
- essay_genre:essay_genres(*)
+ essay_genre:essay_genres(*),
+ content
`)
.eq('id', id)
.single();
if (error) throw error;
setEssay(data);
+
+ // Atualizar contagem de palavras
+ if (data?.content) {
+ const words = data.content.trim().split(/\s+/).length;
+ setWordCount(words);
+ }
} catch (error) {
console.error('Erro ao carregar redação:', error);
} finally {
@@ -114,13 +121,19 @@ export function EssayPage() {
async function submitForAnalysis() {
if (!essay) return;
try {
- // Primeiro atualiza o status
- const { error: updateError } = await supabase
+ setSaving(true);
+
+ // Primeiro salvar o conteúdo atual
+ const { error: saveError } = await supabase
.from('student_essays')
- .update({ status: 'submitted' })
+ .update({
+ title: essay.title,
+ content: essay.content,
+ status: 'submitted'
+ })
.eq('id', essay.id);
- if (updateError) throw updateError;
+ if (saveError) throw saveError;
// Chama a Edge Function para análise
const { error: analysisError } = await supabase.functions.invoke('analyze-essay', {
@@ -138,6 +151,8 @@ export function EssayPage() {
navigate(`/aluno/redacoes/${essay.id}/analise`);
} catch (error) {
console.error('Erro ao enviar para análise:', error);
+ } finally {
+ setSaving(false);
}
}
@@ -217,9 +232,9 @@ export function EssayPage() {
•
•
-
+
@@ -278,16 +293,36 @@ export function EssayPage() {
>
)}
+
+ {essay.status === 'analyzed' && (
+ navigate(`/aluno/redacoes/${essay.id}/analise`)}
+ className="bg-purple-600 hover:bg-purple-700 text-white"
+ trackingId="essay-view-analysis-button"
+ trackingProperties={{
+ action: 'view_analysis',
+ page: 'essay_editor'
+ }}
+ >
+
+
+
+ )}
setEssay({ ...essay, content: newContent })}
- placeholder="Escreva sua redação aqui..."
+ content={essay.content || ''}
+ onChange={(newContent) => essay.status === 'draft' ? setEssay({ ...essay, content: newContent }) : null}
+ placeholder={essay.status === 'draft' ? "Escreva sua redação aqui..." : ""}
readOnly={essay.status !== 'draft'}
+ className={cn(
+ "min-h-[400px]",
+ essay.status !== 'draft' && "bg-gray-50"
+ )}
/>
{wordCount} palavras
- {!isWithinWordLimit && (
+ {essay.status === 'draft' && !isWithinWordLimit && (
{' '}(mínimo: {essay.essay_genre.requirements.min_words},
máximo: {essay.essay_genre.requirements.max_words})