diff --git a/manager/components/Certificates.tsx b/manager/components/Certificates.tsx index 8d077a3..374a3cf 100644 --- a/manager/components/Certificates.tsx +++ b/manager/components/Certificates.tsx @@ -12,6 +12,41 @@ interface CertificatesProps { const Certificates: React.FC = ({ data, updateData }) => { const { showAlert, showConfirm } = useDialog(); + + const [dbClasses, setDbClasses] = useState(data?.classes || []); + const [dbCourses, setDbCourses] = useState(data?.courses || []); + const [dbSubjects, setDbSubjects] = useState(data?.subjects || []); + + React.useEffect(() => { + Promise.all([ + fetch('/api/turmas').catch(() => ({ ok: false, json: async () => ({}) })), + fetch('/api/cursos').catch(() => ({ ok: false, json: async () => ({}) })), + fetch('/api/disciplinas').catch(() => ({ ok: false, json: async () => ({}) })) + ]).then(async (responses) => { + const [resT, resC, resS] = responses; + if (resT && resT.ok) { + const jsonT = await resT.json(); + if (jsonT.turmas) setDbClasses(jsonT.turmas.map((t: any) => ({ + id: t.id, name: t.nome, courseId: t.curso_id, maxStudents: Number(t.max_alunos || 0) + }))); + } + if (resC && resC.ok) { + const jsonC = await resC.json(); + if (jsonC.cursos) setDbCourses(jsonC.cursos.map((c: any) => ({ + id: c.id, name: c.nome, monthlyFee: Number(c.mensalidade || 0), registrationFee: Number(c.taxa_matricula || 0) + }))); + } + + if (resS && resS.ok) { + const jsonS = await resS.json(); + if (jsonS.disciplinas) setDbSubjects(jsonS.disciplinas.map((d: any) => ({ + id: d.id, name: d.nome + }))); + } + + }).catch(console.error); + }, []); + const [searchTerm, setSearchTerm] = useState(''); const [selectedStudentId, setSelectedStudentId] = useState(''); const [description, setDescription] = useState(''); @@ -212,7 +247,7 @@ const Certificates: React.FC = ({ data, updateData }) => { const historico = (data.grades || []) .filter(g => g.studentId === cert.studentId) .map(g => { - const subject = data.subjects.find(s => s.id === g.subjectId); + const subject = dbSubjects.find(s => s.id === g.subjectId); return `${subject?.name || 'Disciplina'}: ${g.value}`; }) .join('\n'); @@ -266,7 +301,7 @@ const Certificates: React.FC = ({ data, updateData }) => { const currentHistorico = (data.grades || []) .filter(g => g.studentId === selectedStudentId) .map(g => { - const subject = data.subjects.find(s => s.id === g.subjectId); + const subject = dbSubjects.find(s => s.id === g.subjectId); return `${subject?.name || 'Disciplina'}: ${g.value}`; }) .join('\n') || 'Matemática: 9.5\nPortuguês: 8.0\nHistória: 10.0'; diff --git a/manager/components/Contracts.tsx b/manager/components/Contracts.tsx index 5653d54..52d7c16 100644 --- a/manager/components/Contracts.tsx +++ b/manager/components/Contracts.tsx @@ -11,6 +11,34 @@ interface ContractsProps { const Contracts: React.FC = ({ data, updateData }) => { const { showAlert, showConfirm } = useDialog(); + + const [dbClasses, setDbClasses] = useState(data?.classes || []); + const [dbCourses, setDbCourses] = useState(data?.courses || []); + + + React.useEffect(() => { + Promise.all([ + fetch('/api/turmas').catch(() => ({ ok: false, json: async () => ({}) })), + fetch('/api/cursos').catch(() => ({ ok: false, json: async () => ({}) })), + + ]).then(async (responses) => { + const [resT, resC] = responses; + if (resT && resT.ok) { + const jsonT = await resT.json(); + if (jsonT.turmas) setDbClasses(jsonT.turmas.map((t: any) => ({ + id: t.id, name: t.nome, courseId: t.curso_id, maxStudents: Number(t.max_alunos || 0) + }))); + } + if (resC && resC.ok) { + const jsonC = await resC.json(); + if (jsonC.cursos) setDbCourses(jsonC.cursos.map((c: any) => ({ + id: c.id, name: c.nome, monthlyFee: Number(c.mensalidade || 0), registrationFee: Number(c.taxa_matricula || 0) + }))); + } + + }).catch(console.error); + }, []); + const [activeTab, setActiveTab] = useState<'contracts' | 'templates'>('contracts'); const [isModalOpen, setIsModalOpen] = useState(false); const [isTemplateModalOpen, setIsTemplateModalOpen] = useState(false); @@ -42,8 +70,8 @@ const Contracts: React.FC = ({ data, updateData }) => { useEffect(() => { if (formData.studentId && !formData.content) { const student = data.students.find(s => s.id === formData.studentId); - const cls = data.classes.find(c => c.id === student?.classId); - const course = data.courses.find(c => c.id === cls?.courseId); + const cls = dbClasses.find(c => c.id === student?.classId); + const course = dbCourses.find(c => c.id === cls?.courseId); const templateObj = data.contractTemplates?.find(t => t.id === student?.contractTemplateId); if (student && course) { @@ -190,8 +218,8 @@ const Contracts: React.FC = ({ data, updateData }) => { const openGenerateModal = (contract: Contract) => { const student = data.students.find(s => s.id === contract.studentId); - const cls = data.classes.find(c => c.id === student?.classId); - const course = data.courses.find(c => c.id === cls?.courseId); + const cls = dbClasses.find(c => c.id === student?.classId); + const course = dbCourses.find(c => c.id === cls?.courseId); if (student && cls && course) { setContractToGenerate(contract); @@ -211,8 +239,8 @@ const Contracts: React.FC = ({ data, updateData }) => { const contract = contractToGenerate; const student = data.students.find(s => s.id === contract.studentId); - const cls = data.classes.find(c => c.id === student?.classId); - const course = data.courses.find(c => c.id === cls?.courseId); + const cls = dbClasses.find(c => c.id === student?.classId); + const course = dbCourses.find(c => c.id === cls?.courseId); if (!course || !student) return; diff --git a/manager/components/Dashboard.tsx b/manager/components/Dashboard.tsx index 54bbbf2..b46582a 100644 --- a/manager/components/Dashboard.tsx +++ b/manager/components/Dashboard.tsx @@ -41,10 +41,27 @@ interface DashboardProps { const Dashboard: React.FC = ({ data }) => { const [isGeneratingPDF, setIsGeneratingPDF] = useState(false); const [dashboardView, setDashboardView] = useState<'standard' | 'detailed'>('standard'); + const [dbClasses, setDbClasses] = useState(data.classes || []); + + React.useEffect(() => { + fetch('/api/turmas') + .then(res => res.json()) + .then(json => { + if (json.turmas) { + setDbClasses(json.turmas.map((t: any) => ({ + id: t.id, + name: t.nome, + courseId: t.curso_id, + maxStudents: Number(t.max_alunos || 0) + }))); + } + }) + .catch(console.error); + }, []); // Basic Stats const activeStudents = useMemo(() => data.students.filter(s => s.status === 'active').length, [data.students]); - const totalClasses = useMemo(() => data.classes.length, [data.classes]); + const totalClasses = useMemo(() => dbClasses.length, [dbClasses]); const pendingPayments = useMemo(() => data.payments.filter(p => p.status === 'pending').length, [data.payments]); const revenue = useMemo(() => data.payments .filter(p => p.status === 'paid') @@ -76,11 +93,11 @@ const Dashboard: React.FC = ({ data }) => { }, [data.lessons]); // Chart Data: Class Occupancy - const classOccupancy = useMemo(() => data.classes.map(c => ({ + const classOccupancy = useMemo(() => dbClasses.map(c => ({ name: c.name, students: data.students.filter(s => s.classId === c.id).length, - capacity: 20 // Assuming a default capacity - })).sort((a, b) => b.students - a.students), [data.classes, data.students]); + capacity: c.maxStudents || 20 // Usando a capacidade real se disponível + })).sort((a, b) => b.students - a.students), [dbClasses, data.students]); // Chart Data: Payment Status const paymentStatus = useMemo(() => [ diff --git a/manager/components/Exams.tsx b/manager/components/Exams.tsx index fe8fdd3..83a3aa5 100644 --- a/manager/components/Exams.tsx +++ b/manager/components/Exams.tsx @@ -20,6 +20,41 @@ const Exams: React.FC = ({ data, updateData }) => { const [activeTab, setActiveTab] = useState<'ativos' | 'lixeira'>('ativos'); const { showAlert, showConfirm } = useDialog(); + const [dbClasses, setDbClasses] = useState(data?.classes || []); + const [dbCourses, setDbCourses] = useState(data?.courses || []); + const [dbSubjects, setDbSubjects] = useState(data?.subjects || []); + + React.useEffect(() => { + Promise.all([ + fetch('/api/turmas').catch(() => ({ ok: false, json: async () => ({}) })), + fetch('/api/cursos').catch(() => ({ ok: false, json: async () => ({}) })), + fetch('/api/disciplinas').catch(() => ({ ok: false, json: async () => ({}) })) + ]).then(async (responses) => { + const [resT, resC, resS] = responses; + if (resT && resT.ok) { + const jsonT = await resT.json(); + if (jsonT.turmas) setDbClasses(jsonT.turmas.map((t: any) => ({ + id: t.id, name: t.nome, courseId: t.curso_id, maxStudents: Number(t.max_alunos || 0) + }))); + } + if (resC && resC.ok) { + const jsonC = await resC.json(); + if (jsonC.cursos) setDbCourses(jsonC.cursos.map((c: any) => ({ + id: c.id, name: c.nome, monthlyFee: Number(c.mensalidade || 0), registrationFee: Number(c.taxa_matricula || 0) + }))); + } + + if (resS && resS.ok) { + const jsonS = await resS.json(); + if (jsonS.disciplinas) setDbSubjects(jsonS.disciplinas.map((d: any) => ({ + id: d.id, name: d.nome + }))); + } + + }).catch(console.error); + }, []); + + const normalizePhotoUrl = (url?: string) => { if (!url) return ''; if (url.startsWith('data:image') || url.startsWith('/storage')) return url; @@ -35,14 +70,14 @@ const Exams: React.FC = ({ data, updateData }) => { const filteredExams = exams.filter(exam => (activeTab === 'ativos' ? !exam.isDeleted : !!exam.isDeleted) && (exam.title.toLowerCase().includes(searchTerm.toLowerCase()) || - data.classes.find(c => c.id === exam.classId)?.name.toLowerCase().includes(searchTerm.toLowerCase())) + dbClasses.find(c => c.id === exam.classId)?.name.toLowerCase().includes(searchTerm.toLowerCase())) ); const handleStartCreate = () => { setEditingExam({ id: Date.now().toString(), title: '', - classId: data.classes[0]?.id || '', + classId: dbClasses[0]?.id || '', durationMinutes: 60, status: 'draft', questions: [], @@ -194,7 +229,7 @@ const Exams: React.FC = ({ data, updateData }) => { }; const handleNotifyStudents = async (exam: Exam) => { - const classObj = (data.classes || []).find(c => c.id === exam.classId); + const classObj = (dbClasses || []).find(c => c.id === exam.classId); if (!classObj) return; showConfirm( @@ -318,7 +353,7 @@ const Exams: React.FC = ({ data, updateData }) => { className="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:ring-2 focus:ring-indigo-500 focus:outline-none transition-all font-medium text-slate-800" > - {data.classes.map(c => ( + {dbClasses.map(c => ( ))} @@ -343,7 +378,7 @@ const Exams: React.FC = ({ data, updateData }) => { className="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:ring-2 focus:ring-indigo-500 focus:outline-none transition-all font-medium text-slate-800" > - {(data.subjects || []).map(s => ( + {(dbSubjects || []).map(s => ( ))} @@ -575,7 +610,7 @@ const Exams: React.FC = ({ data, updateData }) => { ) : (
{filteredExams.map(exam => { - const classObj = data.classes.find(c => c.id === exam.classId); + const classObj = dbClasses.find(c => c.id === exam.classId); return (
@@ -613,7 +648,7 @@ const Exams: React.FC = ({ data, updateData }) => { {exam.subjectId && (

Disciplina: - {(data.subjects || []).find(s => s.id === exam.subjectId)?.name || '—'} + {(dbSubjects || []).find(s => s.id === exam.subjectId)?.name || '—'}

)} {exam.periodId && ( @@ -716,7 +751,7 @@ const Exams: React.FC = ({ data, updateData }) => { onChange={e => setTargetClassId(e.target.value)} className="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:ring-2 focus:ring-indigo-500 focus:outline-none transition-all font-bold text-slate-700" > - {data.classes.map(c => ( + {dbClasses.map(c => ( ))} diff --git a/manager/components/LessonSchedule.tsx b/manager/components/LessonSchedule.tsx index a346565..33c1bcc 100644 --- a/manager/components/LessonSchedule.tsx +++ b/manager/components/LessonSchedule.tsx @@ -13,6 +13,34 @@ interface LessonScheduleProps { const LessonSchedule: React.FC = ({ classObj, data, updateData, onClose }) => { const { showAlert, showConfirm } = useDialog(); + + const [dbClasses, setDbClasses] = useState(data?.classes || []); + const [dbCourses, setDbCourses] = useState(data?.courses || []); + + + React.useEffect(() => { + Promise.all([ + fetch('/api/turmas').catch(() => ({ ok: false, json: async () => ({}) })), + fetch('/api/cursos').catch(() => ({ ok: false, json: async () => ({}) })), + + ]).then(async (responses) => { + const [resT, resC] = responses; + if (resT && resT.ok) { + const jsonT = await resT.json(); + if (jsonT.turmas) setDbClasses(jsonT.turmas.map((t: any) => ({ + id: t.id, name: t.nome, courseId: t.curso_id, maxStudents: Number(t.max_alunos || 0) + }))); + } + if (resC && resC.ok) { + const jsonC = await resC.json(); + if (jsonC.cursos) setDbCourses(jsonC.cursos.map((c: any) => ({ + id: c.id, name: c.nome, monthlyFee: Number(c.mensalidade || 0), registrationFee: Number(c.taxa_matricula || 0) + }))); + } + + }).catch(console.error); + }, []); + const [showGenerateModal, setShowGenerateModal] = useState(false); const [showLessonDetail, setShowLessonDetail] = useState(null); const [isClosing, setIsClosing] = useState(false); @@ -53,7 +81,7 @@ const LessonSchedule: React.FC = ({ classObj, data, updateD // Só dá conflito se for na mesma TURMA ou com o mesmo PROFESSOR const isSameClass = l.classId === classObj.id; - const otherClass = data.classes.find(c => c.id === l.classId); + const otherClass = dbClasses.find(c => c.id === l.classId); const isSameTeacher = otherClass && classObj.teacher && otherClass.teacher === classObj.teacher; if (!isSameClass && !isSameTeacher) return false; diff --git a/manager/components/Messages.tsx b/manager/components/Messages.tsx index 99ab5b5..9ac5e5b 100644 --- a/manager/components/Messages.tsx +++ b/manager/components/Messages.tsx @@ -28,6 +28,34 @@ const defaultTemplates = { const Messages: React.FC = ({ data, updateData }) => { const { showAlert, showConfirm } = useDialog(); + + const [dbClasses, setDbClasses] = useState(data?.classes || []); + const [dbCourses, setDbCourses] = useState(data?.courses || []); + + + React.useEffect(() => { + Promise.all([ + fetch('/api/turmas').catch(() => ({ ok: false, json: async () => ({}) })), + fetch('/api/cursos').catch(() => ({ ok: false, json: async () => ({}) })), + + ]).then(async (responses) => { + const [resT, resC] = responses; + if (resT && resT.ok) { + const jsonT = await resT.json(); + if (jsonT.turmas) setDbClasses(jsonT.turmas.map((t: any) => ({ + id: t.id, name: t.nome, courseId: t.curso_id, maxStudents: Number(t.max_alunos || 0) + }))); + } + if (resC && resC.ok) { + const jsonC = await resC.json(); + if (jsonC.cursos) setDbCourses(jsonC.cursos.map((c: any) => ({ + id: c.id, name: c.nome, monthlyFee: Number(c.mensalidade || 0), registrationFee: Number(c.taxa_matricula || 0) + }))); + } + + }).catch(console.error); + }, []); + const defaultVars = data.messageTemplates || defaultTemplates; const initRules = defaultVars.automationRules || defaultTemplates.automationRules; @@ -356,7 +384,7 @@ const Messages: React.FC = ({ data, updateData }) => { > {targetType === 'turma' - ? data.classes?.map(c => ) + ? dbClasses?.map(c => ) : data.students?.map(s => ) } diff --git a/manager/components/ReportCard.tsx b/manager/components/ReportCard.tsx index 82711dc..92e3ac5 100644 --- a/manager/components/ReportCard.tsx +++ b/manager/components/ReportCard.tsx @@ -41,6 +41,33 @@ const ReportCard: React.FC = ({ data, updateData }) => { const periods = data.periods || []; const grades = data.grades || []; + const [dbClasses, setDbClasses] = useState(data.classes || []); + const [dbCourses, setDbCourses] = useState(data.courses || []); + + const loadClassesAndCourses = async () => { + try { + const [clsRes, crsRes] = await Promise.all([ + fetch('/api/turmas'), + fetch('/api/cursos') + ]); + const clsData = await clsRes.json(); + const crsData = await crsRes.json(); + + if (clsData.turmas) { + setDbClasses(clsData.turmas.map((t: any) => ({ + id: t.id, + name: t.nome, + courseId: t.curso_id + }))); + } + if (crsData.cursos) { + setDbCourses(crsData.cursos); + } + } catch(e) { + console.error('Erro ao buscar turmas/cursos:', e); + } + }; + const loadSubjects = async () => { try { const res = await fetch('/api/disciplinas'); @@ -59,6 +86,7 @@ const ReportCard: React.FC = ({ data, updateData }) => { React.useEffect(() => { loadSubjects(); + loadClassesAndCourses(); }, []); // Buscar todas as notas da turma para mostrar médias na lista @@ -361,7 +389,7 @@ const ReportCard: React.FC = ({ data, updateData }) => { return (totalSum / subjectAverages.length).toFixed(2); }; - const filteredClasses = data.classes.filter(c => + const filteredClasses = dbClasses.filter(c => (c.name || '').toLowerCase().includes((searchTerm || '').toLowerCase()) ); @@ -494,7 +522,7 @@ const ReportCard: React.FC = ({ data, updateData }) => {
{filteredClasses.map(cls => { - const course = data.courses.find(c => c.id === cls.courseId); + const course = dbCourses.find(c => c.id === cls.courseId); const studentCount = data.students.filter(s => s.classId === cls.id).length; return (
= ({ data, updateData }) => {

{cls.name}

-

{course?.name || 'Curso não encontrado'}

+

{course?.nome || course?.name || 'Curso não encontrado'}

diff --git a/manager/components/Students.tsx b/manager/components/Students.tsx index 8a35773..72256d9 100644 --- a/manager/components/Students.tsx +++ b/manager/components/Students.tsx @@ -39,6 +39,27 @@ const Students: React.FC = ({ data, updateData, deepLinkStudentId const [cancellationReason, setCancellationReason] = useState(''); const [selectedClassId, setSelectedClassId] = useState(null); const [isSaving, setIsSaving] = useState(false); + + const [dbClasses, setDbClasses] = useState(dbClasses || []); + const [dbCourses, setDbCourses] = useState(dbCourses || []); + + useEffect(() => { + Promise.all([ + fetch('/api/turmas'), + fetch('/api/cursos') + ]).then(async ([resT, resC]) => { + if(resT.ok && resC.ok) { + const jsonT = await resT.json(); + const jsonC = await resC.json(); + if (jsonT.turmas) setDbClasses(jsonT.turmas.map((t: any) => ({ + id: t.id, name: t.nome, courseId: t.curso_id, maxStudents: Number(t.max_alunos || 0) + }))); + if (jsonC.cursos) setDbCourses(jsonC.cursos.map((c: any) => ({ + id: c.id, name: c.nome + }))); + } + }).catch(console.error); + }, []); // Academic History State const [historyGrades, setHistoryGrades] = useState([]); @@ -818,8 +839,8 @@ const Students: React.FC = ({ data, updateData, deepLinkStudentId } // Process Generate Fee and Contract - const studentClass = data.classes.find(c => c.id === formData.classId); - const course = studentClass ? data.courses.find(c => c.id === studentClass.courseId) : null; + const studentClass = dbClasses.find(c => c.id === formData.classId); + const course = studentClass ? dbCourses.find(c => c.id === studentClass.courseId) : null; if ((formData as any).generateFee && course) { const feeAmount = (course.registrationFee || 0) - (formData.discount || 0); @@ -1173,9 +1194,9 @@ const Students: React.FC = ({ data, updateData, deepLinkStudentId {(activeTab === 'active' && !selectedClassId && !searchTerm) ? (
- {data.classes.map(cls => { + {dbClasses.map(cls => { const studentCount = data.students.filter(s => s.classId === cls.id && (activeTab === 'active' ? s.status !== 'cancelled' : s.status === 'cancelled')).length; - const course = data.courses.find(c => c.id === cls.courseId); + const course = dbCourses.find(c => c.id === cls.courseId); return ( {selectedClassId && (

- {selectedClassId === 'none' ? 'Alunos Sem Turma' : data.classes.find(c => c.id === selectedClassId)?.name} + {selectedClassId === 'none' ? 'Alunos Sem Turma' : dbClasses.find(c => c.id === selectedClassId)?.name}

)}
@@ -1261,7 +1282,7 @@ const Students: React.FC = ({ data, updateData, deepLinkStudentId {filteredStudents.map(student => { - const studentClass = data.classes.find(c => c.id === student.classId); + const studentClass = dbClasses.find(c => c.id === student.classId); return ( @@ -1752,7 +1773,7 @@ const Students: React.FC = ({ data, updateData, deepLinkStudentId onChange={e => setFormData({...formData, classId: e.target.value})} > - {data.classes.map(c => ( + {dbClasses.map(c => ( ))} @@ -1873,7 +1894,7 @@ const Students: React.FC = ({ data, updateData, deepLinkStudentId onChange={e => setNewClassId(e.target.value)} > - {data.classes.filter(c => c.id !== transferringStudent.classId).map(c => ( + {dbClasses.filter(c => c.id !== transferringStudent.classId).map(c => ( ))} diff --git a/manager/scratch/update_others.cjs b/manager/scratch/update_others.cjs new file mode 100644 index 0000000..de4f381 --- /dev/null +++ b/manager/scratch/update_others.cjs @@ -0,0 +1,74 @@ +const fs = require('fs'); +const path = require('path'); + +function processFile(filename, replaceSubjects = false) { + const filePath = path.join(__dirname, '../components', filename); + if (!fs.existsSync(filePath)) return; + + let content = fs.readFileSync(filePath, 'utf8'); + + // Inject states and fetch + // Find a good place to inject. Usually after `const [isModalOpen, setIsModalOpen] = useState(false);` or similar. + // We'll just look for a known pattern or add it at the top of the component. + + // We will find `const { showAlert, showConfirm } = useDialog();` and inject right after it + const hookDecl = `const { showAlert, showConfirm } = useDialog();`; + + let fetchBlock = ` + const [dbClasses, setDbClasses] = useState(data?.classes || []); + const [dbCourses, setDbCourses] = useState(data?.courses || []); + ${replaceSubjects ? 'const [dbSubjects, setDbSubjects] = useState(data?.subjects || []);' : ''} + + React.useEffect(() => { + Promise.all([ + fetch('/api/turmas').catch(() => ({ ok: false, json: async () => ({}) })), + fetch('/api/cursos').catch(() => ({ ok: false, json: async () => ({}) })), + ${replaceSubjects ? "fetch('/api/disciplinas').catch(() => ({ ok: false, json: async () => ({}) }))" : ''} + ]).then(async (responses) => { + const [resT, resC${replaceSubjects ? ', resS' : ''}] = responses; + if (resT && resT.ok) { + const jsonT = await resT.json(); + if (jsonT.turmas) setDbClasses(jsonT.turmas.map((t: any) => ({ + id: t.id, name: t.nome, courseId: t.curso_id, maxStudents: Number(t.max_alunos || 0) + }))); + } + if (resC && resC.ok) { + const jsonC = await resC.json(); + if (jsonC.cursos) setDbCourses(jsonC.cursos.map((c: any) => ({ + id: c.id, name: c.nome, monthlyFee: Number(c.mensalidade || 0), registrationFee: Number(c.taxa_matricula || 0) + }))); + } + ${replaceSubjects ? ` + if (resS && resS.ok) { + const jsonS = await resS.json(); + if (jsonS.disciplinas) setDbSubjects(jsonS.disciplinas.map((d: any) => ({ + id: d.id, name: d.nome + }))); + } + ` : ''} + }).catch(console.error); + }, []); + `; + + if (content.includes(hookDecl) && !content.includes('const [dbClasses')) { + content = content.replace(hookDecl, hookDecl + '\n' + fetchBlock); + + // Replace usages + content = content.replace(/data\.classes/g, 'dbClasses'); + content = content.replace(/data\.courses/g, 'dbCourses'); + if (replaceSubjects) { + content = content.replace(/data\.subjects/g, 'dbSubjects'); + } + + fs.writeFileSync(filePath, content, 'utf8'); + console.log(filename + ' atualizado.'); + } +} + +processFile('Finance.tsx', false); +processFile('Exams.tsx', true); +processFile('Contracts.tsx', false); +processFile('LessonSchedule.tsx', false); +processFile('AttendanceQuery.tsx', false); +processFile('Certificates.tsx', true); +processFile('Messages.tsx', false); diff --git a/manager/scratch/update_students.cjs b/manager/scratch/update_students.cjs new file mode 100644 index 0000000..43701cc --- /dev/null +++ b/manager/scratch/update_students.cjs @@ -0,0 +1,42 @@ +const fs = require('fs'); +const path = require('path'); + +const filePath = path.join(__dirname, '../components/Students.tsx'); +let content = fs.readFileSync(filePath, 'utf8'); + +// Adicionar os states +const stateCode = ` const [isSaving, setIsSaving] = useState(false); + + const [dbClasses, setDbClasses] = useState(data.classes || []); + const [dbCourses, setDbCourses] = useState(data.courses || []); + + useEffect(() => { + Promise.all([ + fetch('/api/turmas'), + fetch('/api/cursos') + ]).then(async ([resT, resC]) => { + if(resT.ok && resC.ok) { + const jsonT = await resT.json(); + const jsonC = await resC.json(); + if (jsonT.turmas) setDbClasses(jsonT.turmas.map((t: any) => ({ + id: t.id, name: t.nome, courseId: t.curso_id, maxStudents: Number(t.max_alunos || 0) + }))); + if (jsonC.cursos) setDbCourses(jsonC.cursos.map((c: any) => ({ + id: c.id, name: c.nome + }))); + } + }).catch(console.error); + }, []);`; + +content = content.replace(' const [isSaving, setIsSaving] = useState(false);', stateCode); + +// Substituições seguras +content = content.replace(/data\.classes/g, 'dbClasses'); +content = content.replace(/data\.courses/g, 'dbCourses'); + +// E arrumar uma possível falha caso haja "dbClasses" onde deveria ser data.classes no destructuring ou useEffect dependencias +// Por exemplo: se ele usava deepLinkClassId dependendo de data.classes +content = content.replace(/dbClasses, dbCourses, data\.students/g, 'dbClasses, dbCourses, data.students'); + +fs.writeFileSync(filePath, content, 'utf8'); +console.log('Students.tsx atualizado com sucesso.');