From e2cb0376cf68b3c095e786a96938455830fcb62c Mon Sep 17 00:00:00 2001 From: Sidney Date: Fri, 1 May 2026 11:00:29 -0300 Subject: [PATCH] =?UTF-8?q?fix:=20robustez=20nos=20IDs=20(trim)=20e=20subs?= =?UTF-8?q?titui=C3=A7=C3=A3o=20de=20=C3=ADcone=20Loader2=20por=20RefreshC?= =?UTF-8?q?w=20para=20compatibilidade?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manager/components/ReportCard.tsx | 12 ++++++------ manager/scratch/check_counts.js | 13 +++++++++++++ manager/scratch/list_all.js | 17 +++++++++++++++++ manager/server.selfhosted.js | 8 ++++---- portal/server.selfhosted.js | 6 +++--- portal/src/pages/Avaliacoes.tsx | 4 ++-- 6 files changed, 45 insertions(+), 15 deletions(-) create mode 100644 manager/scratch/check_counts.js create mode 100644 manager/scratch/list_all.js diff --git a/manager/components/ReportCard.tsx b/manager/components/ReportCard.tsx index 60cf7a9..e812054 100644 --- a/manager/components/ReportCard.tsx +++ b/manager/components/ReportCard.tsx @@ -144,15 +144,15 @@ const ReportCard: React.FC = ({ data, updateData }) => { initialGrades[subject.id] = {}; periods.forEach(period => { const periodGrades: any = {}; - const linkedExams = (data.exams || []).filter(e => String(e.subjectId) === String(subject.id) && String(e.periodId) === String(period.id) && e.status === 'published'); + const linkedExams = (data.exams || []).filter(e => String(e.subjectId).trim() === String(subject.id).trim() && String(e.periodId).trim() === String(period.id).trim() && e.status === 'published'); if (linkedExams.length > 0) { linkedExams.forEach(exam => { - const existingGrade = dbNotas.find(g => String(g.disciplina_id) === String(subject.id) && String(g.periodo_id) === String(period.id) && String(g.prova_id) === String(exam.id)); + const existingGrade = dbNotas.find(g => String(g.disciplina_id).trim() === String(subject.id).trim() && String(g.periodo_id).trim() === String(period.id).trim() && String(g.prova_id).trim() === String(exam.id).trim()); periodGrades[exam.id] = existingGrade ? Number(existingGrade.valor) : ''; }); } else { - const existingGrade = dbNotas.find(g => String(g.disciplina_id) === String(subject.id) && String(g.periodo_id) === String(period.id) && !g.prova_id); + const existingGrade = dbNotas.find(g => String(g.disciplina_id).trim() === String(subject.id).trim() && String(g.periodo_id).trim() === String(period.id).trim() && !g.prova_id); periodGrades['direct'] = existingGrade ? Number(existingGrade.valor) : ''; } initialGrades[subject.id][period.id] = periodGrades; @@ -518,7 +518,7 @@ const ReportCard: React.FC = ({ data, updateData }) => {
{subjects.map(subject => { // Encontrar provas vinculadas a esta disciplina - const linkedExams = (data.exams || []).filter(e => String(e.subjectId) === String(subject.id) && e.status === 'published'); + const linkedExams = (data.exams || []).filter(e => String(e.subjectId).trim() === String(subject.id).trim() && e.status === 'published'); return (
@@ -529,7 +529,7 @@ const ReportCard: React.FC = ({ data, updateData }) => {
{(() => { - const linkedExams = (data.exams || []).filter(e => String(e.subjectId) === String(subject.id) && e.status === 'published'); + const linkedExams = (data.exams || []).filter(e => String(e.subjectId).trim() === String(subject.id).trim() && e.status === 'published'); const provasCount = linkedExams.filter(e => (e as any).evaluationType !== 'activity').length; const atividadesCount = linkedExams.filter(e => (e as any).evaluationType === 'activity').length; return ( @@ -561,7 +561,7 @@ const ReportCard: React.FC = ({ data, updateData }) => {
{periods.map(period => { - const linkedExams = (data.exams || []).filter(e => String(e.subjectId) === String(subject.id) && String(e.periodId) === String(period.id) && e.status === 'published'); + const linkedExams = (data.exams || []).filter(e => String(e.subjectId).trim() === String(subject.id).trim() && String(e.periodId).trim() === String(period.id).trim() && e.status === 'published'); const periodGrades = studentGrades[subject.id]?.[period.id] || {}; const periodSum: number = Object.values(periodGrades).reduce((a, b: any) => a + (b !== '' ? Number(b) : 0), 0); diff --git a/manager/scratch/check_counts.js b/manager/scratch/check_counts.js new file mode 100644 index 0000000..13c5fea --- /dev/null +++ b/manager/scratch/check_counts.js @@ -0,0 +1,13 @@ +import pg from 'pg'; +const DATABASE_URL = 'postgresql://edumanager:EduManager2026!Seguro@127.0.0.1:5432/edumanager'; +const pool = new pg.Pool({ connectionString: DATABASE_URL }); +async function check() { + try { + const { rows } = await pool.query(\"SELECT (data->'grades') as grades FROM school_data WHERE id = 1\"); + console.log('GRADES_JSON_COUNT:' + (rows[0]?.grades?.length || 0)); + const { rows: n } = await pool.query(\"SELECT count(*) FROM notas_boletim\"); + console.log('NOTAS_TABLE_COUNT:' + n[0].count); + } catch (err) { console.log('ERROR:' + err.message); } + finally { await pool.end(); } +} +check(); diff --git a/manager/scratch/list_all.js b/manager/scratch/list_all.js new file mode 100644 index 0000000..7c5f404 --- /dev/null +++ b/manager/scratch/list_all.js @@ -0,0 +1,17 @@ +import pg from 'pg'; +const DATABASE_URL = 'postgresql://edumanager:EduManager2026!Seguro@127.0.0.1:5432/edumanager'; +const pool = new pg.Pool({ connectionString: DATABASE_URL }); + +async function listAll() { + try { + const { rows: notas } = await pool.query('SELECT * FROM notas_boletim LIMIT 20'); + console.log('--- NOTAS NA TABELA ---'); + console.log(JSON.stringify(notas, null, 2)); + + const { rows: subs } = await pool.query('SELECT * FROM provas_submissoes LIMIT 10'); + console.log('--- SUBMISSÕES NA TABELA ---'); + console.log(JSON.stringify(subs, null, 2)); + } catch (err) { console.log('ERROR:' + err.message); } + finally { await pool.end(); } +} +listAll(); diff --git a/manager/server.selfhosted.js b/manager/server.selfhosted.js index 4196c7c..cd82c32 100644 --- a/manager/server.selfhosted.js +++ b/manager/server.selfhosted.js @@ -306,8 +306,8 @@ app.get('/api/student-submissions/:studentId', async (req, res) => { try { const { studentId } = req.params; const { rows } = await pool.query( - 'SELECT prova_id as "prova_id", acertos, erros FROM provas_submissoes WHERE aluno_id = $1', - [String(studentId)] + 'SELECT prova_id as "prova_id", acertos, erros FROM provas_submissoes WHERE TRIM(aluno_id) = TRIM($1)', + [String(studentId).trim()] ); res.json({ submissions: rows }); } catch (err) { @@ -322,8 +322,8 @@ app.get('/api/student-submissions/:studentId', async (req, res) => { app.get('/api/notas/:alunoId', async (req, res) => { try { const { rows: dbNotas } = await pool.query( - 'SELECT id, aluno_id as "aluno_id", disciplina_id as "disciplina_id", periodo_id as "periodo_id", prova_id as "prova_id", valor as "valor" FROM notas_boletim WHERE aluno_id = $1', - [req.params.alunoId] + 'SELECT id, aluno_id as "aluno_id", disciplina_id as "disciplina_id", periodo_id as "periodo_id", prova_id as "prova_id", valor as "valor" FROM notas_boletim WHERE TRIM(aluno_id) = TRIM($1)', + [String(req.params.alunoId).trim()] ); // Garantir cast numérico para evitar erro de .toFixed no frontend const notas = dbNotas.map(n => ({ ...n, valor: Number(n.valor) })); diff --git a/portal/server.selfhosted.js b/portal/server.selfhosted.js index 0716d8e..115d9ca 100644 --- a/portal/server.selfhosted.js +++ b/portal/server.selfhosted.js @@ -264,9 +264,9 @@ app.get('/api/portal/notas', authMiddleware, async (req, res) => { ); const enrichedGrades = grades.map((g) => { - const subject = subjects.find((s) => String(s.id) === String(g.subjectId)); - const exam = g.examId ? (schoolData.exams || []).find(e => String(e.id) === String(g.examId)) : null; - const periodObj = (schoolData.periods || []).find(p => String(p.id) === String(g.period)); + const subject = subjects.find((s) => String(s.id).trim() === String(g.subjectId).trim()); + const exam = g.examId ? (schoolData.exams || []).find(e => String(e.id).trim() === String(g.examId).trim()) : null; + const periodObj = (schoolData.periods || []).find(p => String(p.id).trim() === String(g.period).trim()); const submission = g.examId ? submissions.find(s => String(s.prova_id) === String(g.examId)) : null; diff --git a/portal/src/pages/Avaliacoes.tsx b/portal/src/pages/Avaliacoes.tsx index 8572589..347b2fa 100644 --- a/portal/src/pages/Avaliacoes.tsx +++ b/portal/src/pages/Avaliacoes.tsx @@ -3,7 +3,7 @@ import { useAuth } from '../context/AuthContext'; import type { Exam, ExamSubmission } from '../types'; import { ClipboardList, Clock, ChevronLeft, ChevronRight, Send, CheckCircle2, - XCircle, Award, AlertTriangle, Timer, ArrowLeft, Loader2 + XCircle, Award, AlertTriangle, Timer, ArrowLeft, RefreshCw } from 'lucide-react'; import { normalizePhotoUrl } from '../helpers'; @@ -465,7 +465,7 @@ export default function Avaliacoes() { : modalType === 'confirm' ? : modalType === 'loading' - ? + ? : }