diff --git a/src/components/dashboard/WritingMetricsChart.tsx b/src/components/dashboard/WritingMetricsChart.tsx new file mode 100644 index 0000000..c119199 --- /dev/null +++ b/src/components/dashboard/WritingMetricsChart.tsx @@ -0,0 +1,237 @@ +import React from 'react'; +import { Calendar, HelpCircle } from 'lucide-react'; +import { Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, Bar, ComposedChart } from 'recharts'; +import type { WeeklyWritingMetrics } from '@/types/metrics'; + +interface MetricConfig { + key: string; + name: string; + color: string; +} + +type TimeFilter = '3m' | '6m' | '12m' | 'all'; + +interface TimeFilterOption { + value: TimeFilter; + label: string; + months: number | null; +} + +const METRICS_CONFIG: MetricConfig[] = [ + { key: 'score', name: 'Nota Geral', color: '#6366f1' }, + { key: 'adequacy', name: 'Adequação', color: '#f43f5e' }, + { key: 'coherence', name: 'Coerência', color: '#0ea5e9' }, + { key: 'cohesion', name: 'Coesão', color: '#10b981' }, + { key: 'vocabulary', name: 'Vocabulário', color: '#8b5cf6' }, + { key: 'grammar', name: 'Gramática', color: '#f59e0b' } +]; + +const TIME_FILTERS: TimeFilterOption[] = [ + { value: '3m', label: '3 meses', months: 3 }, + { value: '6m', label: '6 meses', months: 6 }, + { value: '12m', label: '12 meses', months: 12 }, + { value: 'all', label: 'Todo período', months: null }, +]; + +interface WritingMetricsChartProps { + data: WeeklyWritingMetrics[]; + className?: string; +} + +export function WritingMetricsChart({ data, className = '' }: WritingMetricsChartProps) { + const [visibleMetrics, setVisibleMetrics] = React.useState>( + new Set(METRICS_CONFIG.map(metric => metric.key)) + ); + const [timeFilter, setTimeFilter] = React.useState('12m'); + + const toggleMetric = (metricKey: string) => { + setVisibleMetrics(prev => { + const newSet = new Set(prev); + if (newSet.has(metricKey)) { + newSet.delete(metricKey); + } else { + newSet.add(metricKey); + } + return newSet; + }); + }; + + const filterDataByTime = (data: WeeklyWritingMetrics[]): WeeklyWritingMetrics[] => { + if (timeFilter === 'all') return data; + + const months = TIME_FILTERS.find(f => f.value === timeFilter)?.months || 12; + const cutoffDate = new Date(); + cutoffDate.setMonth(cutoffDate.getMonth() - months); + + return data.filter(item => { + const [year, week] = item.week.split('-W').map(Number); + const itemDate = new Date(year, 0, 1 + (week - 1) * 7); + return itemDate >= cutoffDate; + }); + }; + + const filteredData = filterDataByTime(data); + + return ( +
+
+
+
+

Evolução da Escrita por Semana

+

Acompanhe seu progresso na escrita ao longo do tempo

+
+
+ {/* Filtro de Período */} +
+ + {TIME_FILTERS.map(filter => ( + + ))} +
+
+ +
+
+
+ + {/* Pill Buttons */} +
+ {METRICS_CONFIG.map(metric => ( + + ))} +
+ +
+ + + + + + + + + + + + + { + const metricNames: { [key: string]: string } = { + score: 'Nota Geral', + adequacy: 'Adequação', + coherence: 'Coerência', + cohesion: 'Coesão', + vocabulary: 'Vocabulário', + grammar: 'Gramática', + minutesWriting: 'Minutos Escrevendo' + }; + return [value, metricNames[name] || name]; + }} + contentStyle={{ + backgroundColor: 'rgba(255, 255, 255, 0.98)', + border: 'none', + borderRadius: '8px', + boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)', + padding: '12px' + }} + isAnimationActive={false} + /> + + {METRICS_CONFIG.map(metric => ( + visibleMetrics.has(metric.key) && ( + + ) + ))} + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/src/components/dashboard/WritingMetricsSection.tsx b/src/components/dashboard/WritingMetricsSection.tsx new file mode 100644 index 0000000..c0d8475 --- /dev/null +++ b/src/components/dashboard/WritingMetricsSection.tsx @@ -0,0 +1,143 @@ +import React from 'react'; +import { BookOpen, Clock, TrendingUp, Award, Target, Brain, Gauge, Sparkles, Puzzle, Pencil, HelpCircle } from 'lucide-react'; +import { MetricCard } from './MetricCard'; +import type { WritingMetrics } from '@/types/metrics'; + +interface WritingMetricsSectionProps { + data: WritingMetrics; + className?: string; +} + +const MAIN_METRICS = [ + { + key: 'totalEssays', + title: 'Total de Redações', + getValue: (data: WritingMetrics) => data.totalEssays, + icon: BookOpen, + iconColor: 'text-purple-600', + iconBgColor: 'bg-purple-100' + }, + { + key: 'averageScore', + title: 'Nota Média', + getValue: (data: WritingMetrics) => `${data.averageScore}%`, + icon: TrendingUp, + iconColor: 'text-green-600', + iconBgColor: 'bg-green-100' + }, + { + key: 'totalEssaysTime', + title: 'Tempo de Escrita', + getValue: (data: WritingMetrics) => `${data.totalEssaysTime}min`, + icon: Clock, + iconColor: 'text-blue-600', + iconBgColor: 'bg-blue-100' + }, + { + key: 'currentWritingLevel', + title: 'Nível de Escrita', + getValue: (data: WritingMetrics) => data.currentWritingLevel, + icon: Award, + iconColor: 'text-yellow-600', + iconBgColor: 'bg-yellow-100' + } +]; + +const DETAILED_METRICS = [ + { + key: 'averageAdequacy', + title: 'Adequação ao Tema', + getValue: (data: WritingMetrics) => `${data.averageAdequacy}%`, + icon: Target, + iconColor: 'text-indigo-600', + iconBgColor: 'bg-indigo-100', + tooltip: 'Avalia o quanto sua redação está alinhada com o tema e gênero propostos' + }, + { + key: 'averageCoherence', + title: 'Coerência', + getValue: (data: WritingMetrics) => `${data.averageCoherence}%`, + icon: Brain, + iconColor: 'text-pink-600', + iconBgColor: 'bg-pink-100', + tooltip: 'Indica a clareza e lógica no desenvolvimento das ideias do texto' + }, + { + key: 'averageCohesion', + title: 'Coesão', + getValue: (data: WritingMetrics) => `${data.averageCohesion}%`, + icon: Puzzle, + iconColor: 'text-orange-600', + iconBgColor: 'bg-orange-100', + tooltip: 'Avalia o uso adequado de conectivos e elementos de ligação entre as partes do texto' + }, + { + key: 'averageVocabulary', + title: 'Vocabulário', + getValue: (data: WritingMetrics) => `${data.averageVocabulary}%`, + icon: Sparkles, + iconColor: 'text-cyan-600', + iconBgColor: 'bg-cyan-100', + tooltip: 'Analisa a riqueza e adequação do vocabulário utilizado' + }, + { + key: 'averageGrammar', + title: 'Gramática', + getValue: (data: WritingMetrics) => `${data.averageGrammar}%`, + icon: Pencil, + iconColor: 'text-amber-600', + iconBgColor: 'bg-amber-100', + tooltip: 'Avalia o uso correto das regras gramaticais e ortográficas' + } +]; + +export function WritingMetricsSection({ data, className = '' }: WritingMetricsSectionProps) { + return ( +
+
+

Métricas de Escrita

+ + {/* Métricas Principais */} +
+ {MAIN_METRICS.map(metric => ( + + ))} +
+ + {/* Métricas Detalhadas */} +
+
+

Métricas Detalhadas de Escrita

+
+ +
+
+ +
+ {DETAILED_METRICS.map(metric => ( + + ))} +
+
+
+
+ ); +} \ No newline at end of file diff --git a/src/pages/student-dashboard/StudentDashboardPage.tsx b/src/pages/student-dashboard/StudentDashboardPage.tsx index fd76f3c..1b3c365 100644 --- a/src/pages/student-dashboard/StudentDashboardPage.tsx +++ b/src/pages/student-dashboard/StudentDashboardPage.tsx @@ -5,6 +5,8 @@ import { supabase } from '../../lib/supabase'; import type { Story, Student } from '../../types/database'; import { MetricsChart } from '@/components/dashboard/MetricsChart'; import { DashboardMetrics } from '@/components/dashboard/DashboardMetrics'; +import { WritingMetricsSection } from '@/components/dashboard/WritingMetricsSection'; +import { WritingMetricsChart } from '@/components/dashboard/WritingMetricsChart'; import type { DashboardMetrics as DashboardMetricsType, DashboardWeeklyMetrics, @@ -342,11 +344,27 @@ export function StudentDashboardPage() { - {/* Métricas */} - + {/* Seção de Métricas de Leitura */} +
+

Métricas de Leitura

+ + {/* Métricas de Leitura */} + - {/* Gráfico de Evolução */} - + {/* Gráfico de Evolução da Leitura */} + +
+ + {/* Seção de Métricas de Escrita */} +
+

Métricas de Escrita

+ + {/* Métricas de Escrita */} + + + {/* Gráfico de Evolução da Escrita */} + +
{/* Histórias Recentes */}