fix: robustez nos IDs (trim) e substituição de ícone Loader2 por RefreshCw para compatibilidade
This commit is contained in:
parent
26dc4210eb
commit
e2cb0376cf
|
|
@ -144,15 +144,15 @@ const ReportCard: React.FC<ReportCardProps> = ({ data, updateData }) => {
|
||||||
initialGrades[subject.id] = {};
|
initialGrades[subject.id] = {};
|
||||||
periods.forEach(period => {
|
periods.forEach(period => {
|
||||||
const periodGrades: any = {};
|
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) {
|
if (linkedExams.length > 0) {
|
||||||
linkedExams.forEach(exam => {
|
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) : '';
|
periodGrades[exam.id] = existingGrade ? Number(existingGrade.valor) : '';
|
||||||
});
|
});
|
||||||
} else {
|
} 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) : '';
|
periodGrades['direct'] = existingGrade ? Number(existingGrade.valor) : '';
|
||||||
}
|
}
|
||||||
initialGrades[subject.id][period.id] = periodGrades;
|
initialGrades[subject.id][period.id] = periodGrades;
|
||||||
|
|
@ -518,7 +518,7 @@ const ReportCard: React.FC<ReportCardProps> = ({ data, updateData }) => {
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{subjects.map(subject => {
|
{subjects.map(subject => {
|
||||||
// Encontrar provas vinculadas a esta disciplina
|
// 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 (
|
return (
|
||||||
<div key={subject.id} className="bg-slate-50 rounded-2xl p-6 border border-slate-100 space-y-4">
|
<div key={subject.id} className="bg-slate-50 rounded-2xl p-6 border border-slate-100 space-y-4">
|
||||||
|
|
@ -529,7 +529,7 @@ const ReportCard: React.FC<ReportCardProps> = ({ data, updateData }) => {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{(() => {
|
{(() => {
|
||||||
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 provasCount = linkedExams.filter(e => (e as any).evaluationType !== 'activity').length;
|
||||||
const atividadesCount = linkedExams.filter(e => (e as any).evaluationType === 'activity').length;
|
const atividadesCount = linkedExams.filter(e => (e as any).evaluationType === 'activity').length;
|
||||||
return (
|
return (
|
||||||
|
|
@ -561,7 +561,7 @@ const ReportCard: React.FC<ReportCardProps> = ({ data, updateData }) => {
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-6">
|
<div className="flex flex-col gap-6">
|
||||||
{periods.map(period => {
|
{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 periodGrades = studentGrades[subject.id]?.[period.id] || {};
|
||||||
const periodSum: number = Object.values(periodGrades).reduce<number>((a, b: any) => a + (b !== '' ? Number(b) : 0), 0);
|
const periodSum: number = Object.values(periodGrades).reduce<number>((a, b: any) => a + (b !== '' ? Number(b) : 0), 0);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
@ -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();
|
||||||
|
|
@ -306,8 +306,8 @@ app.get('/api/student-submissions/:studentId', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { studentId } = req.params;
|
const { studentId } = req.params;
|
||||||
const { rows } = await pool.query(
|
const { rows } = await pool.query(
|
||||||
'SELECT prova_id as "prova_id", acertos, erros FROM provas_submissoes WHERE aluno_id = $1',
|
'SELECT prova_id as "prova_id", acertos, erros FROM provas_submissoes WHERE TRIM(aluno_id) = TRIM($1)',
|
||||||
[String(studentId)]
|
[String(studentId).trim()]
|
||||||
);
|
);
|
||||||
res.json({ submissions: rows });
|
res.json({ submissions: rows });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
@ -322,8 +322,8 @@ app.get('/api/student-submissions/:studentId', async (req, res) => {
|
||||||
app.get('/api/notas/:alunoId', async (req, res) => {
|
app.get('/api/notas/:alunoId', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { rows: dbNotas } = await pool.query(
|
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',
|
'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)',
|
||||||
[req.params.alunoId]
|
[String(req.params.alunoId).trim()]
|
||||||
);
|
);
|
||||||
// Garantir cast numérico para evitar erro de .toFixed no frontend
|
// Garantir cast numérico para evitar erro de .toFixed no frontend
|
||||||
const notas = dbNotas.map(n => ({ ...n, valor: Number(n.valor) }));
|
const notas = dbNotas.map(n => ({ ...n, valor: Number(n.valor) }));
|
||||||
|
|
|
||||||
|
|
@ -264,9 +264,9 @@ app.get('/api/portal/notas', authMiddleware, async (req, res) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const enrichedGrades = grades.map((g) => {
|
const enrichedGrades = grades.map((g) => {
|
||||||
const subject = subjects.find((s) => String(s.id) === String(g.subjectId));
|
const subject = subjects.find((s) => String(s.id).trim() === String(g.subjectId).trim());
|
||||||
const exam = g.examId ? (schoolData.exams || []).find(e => String(e.id) === String(g.examId)) : null;
|
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) === String(g.period));
|
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;
|
const submission = g.examId ? submissions.find(s => String(s.prova_id) === String(g.examId)) : null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { useAuth } from '../context/AuthContext';
|
||||||
import type { Exam, ExamSubmission } from '../types';
|
import type { Exam, ExamSubmission } from '../types';
|
||||||
import {
|
import {
|
||||||
ClipboardList, Clock, ChevronLeft, ChevronRight, Send, CheckCircle2,
|
ClipboardList, Clock, ChevronLeft, ChevronRight, Send, CheckCircle2,
|
||||||
XCircle, Award, AlertTriangle, Timer, ArrowLeft, Loader2
|
XCircle, Award, AlertTriangle, Timer, ArrowLeft, RefreshCw
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { normalizePhotoUrl } from '../helpers';
|
import { normalizePhotoUrl } from '../helpers';
|
||||||
|
|
||||||
|
|
@ -465,7 +465,7 @@ export default function Avaliacoes() {
|
||||||
: modalType === 'confirm'
|
: modalType === 'confirm'
|
||||||
? <AlertTriangle size={28} color="var(--color-warning)" />
|
? <AlertTriangle size={28} color="var(--color-warning)" />
|
||||||
: modalType === 'loading'
|
: modalType === 'loading'
|
||||||
? <Loader2 size={28} color="var(--color-primary)" className="animate-spin" />
|
? <RefreshCw size={28} color="var(--color-primary)" className="animate-spin" />
|
||||||
: <CheckCircle2 size={28} color="var(--color-primary)" />
|
: <CheckCircle2 size={28} color="var(--color-primary)" />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue