import React, { useState, useRef } from 'react'; import { SchoolData, Exam, Question } from '../types'; import { FileText, Plus, Search, BookOpen, Upload, Trash2, ArrowLeft, Save, CheckCircle, Image as ImageIcon, X } from 'lucide-react'; import { uploadExamImage } from '../services/supabase'; interface ExamsProps { data: SchoolData; updateData: (newData: Partial) => void; } const Exams: React.FC = ({ data, updateData }) => { const [searchTerm, setSearchTerm] = useState(''); const [currentView, setCurrentView] = useState<'list' | 'builder'>('list'); const [editingExam, setEditingExam] = useState(null); const [isUploading, setIsUploading] = useState(false); const normalizePhotoUrl = (url?: string) => { if (!url) return ''; if (url.startsWith('data:image') || url.startsWith('/storage')) return url; try { const match = url.match(/^https?:\/\/[^\/]+\/(.+)$/); if (match) return `/storage/${match[1]}`; } catch (e) { } return url; }; const exams = data.exams || []; const filteredExams = exams.filter(exam => exam.title.toLowerCase().includes(searchTerm.toLowerCase()) || data.classes.find(c => c.id === exam.classId)?.name.toLowerCase().includes(searchTerm.toLowerCase()) ); const handleStartCreate = () => { setEditingExam({ id: Date.now().toString(), title: '', classId: data.classes[0]?.id || '', durationMinutes: 60, status: 'draft', questions: [], evaluationType: 'exam', maxScore: 10 } as any); setCurrentView('builder'); }; const handleEditExam = (exam: Exam) => { setEditingExam({ ...exam }); setCurrentView('builder'); }; const handleAddQuestion = () => { if (!editingExam) return; setEditingExam({ ...editingExam, questions: [ ...editingExam.questions, { id: Date.now().toString() + Math.random().toString(36).substring(7), text: '', options: ['', '', '', ''], correctOptionIndex: 0 } ] }); }; const handleRemoveQuestion = (qIndex: number) => { if (!editingExam) return; const newQuestions = [...editingExam.questions]; newQuestions.splice(qIndex, 1); setEditingExam({ ...editingExam, questions: newQuestions }); }; const handleQuestionChange = (qIndex: number, field: keyof Question, value: any) => { if (!editingExam) return; const newQuestions = [...editingExam.questions]; newQuestions[qIndex] = { ...newQuestions[qIndex], [field]: value }; setEditingExam({ ...editingExam, questions: newQuestions }); }; const handleOptionChange = (qIndex: number, oIndex: number, value: string) => { if (!editingExam) return; const newQuestions = [...editingExam.questions]; const newOptions = [...newQuestions[qIndex].options]; newOptions[oIndex] = value; newQuestions[qIndex].options = newOptions; setEditingExam({ ...editingExam, questions: newQuestions }); }; const handleAddOption = (qIndex: number) => { if (!editingExam) return; const newQuestions = [...editingExam.questions]; newQuestions[qIndex].options.push(''); setEditingExam({ ...editingExam, questions: newQuestions }); }; const handleRemoveOption = (qIndex: number, oIndex: number) => { if (!editingExam) return; const newQuestions = [...editingExam.questions]; newQuestions[qIndex].options.splice(oIndex, 1); // Adjust correctOptionIndex if needed if (newQuestions[qIndex].correctOptionIndex >= newQuestions[qIndex].options.length) { newQuestions[qIndex].correctOptionIndex = Math.max(0, newQuestions[qIndex].options.length - 1); } else if (newQuestions[qIndex].correctOptionIndex === oIndex) { newQuestions[qIndex].correctOptionIndex = 0; } setEditingExam({ ...editingExam, questions: newQuestions }); }; const handleImageUpload = async (qIndex: number, event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) return; setIsUploading(true); try { const url = await uploadExamImage(file); if (url) { handleQuestionChange(qIndex, 'imageUrl', url); } else { alert('Falha ao obter URL pública da imagem após o upload.'); } } catch (error: any) { console.error(error); const errorMessage = error.message || 'Erro desconhecido'; alert(`Erro ao enviar imagem: ${errorMessage}\n\nVerifique sua conexão ou a configuração do bucket "exames" no MinIO.`); } finally { setIsUploading(false); if (event.target) { event.target.value = ''; // Reset file input } } }; const handleSave = (status: 'draft' | 'published') => { if (!editingExam) return; if (!editingExam.title || !editingExam.classId) { alert('Preencha o título e a turma antes de salvar.'); return; } const finalExam = { ...editingExam, status }; const currentExams = data.exams || []; const existingIndex = currentExams.findIndex(e => e.id === finalExam.id); let newExams; if (existingIndex >= 0) { newExams = [...currentExams]; newExams[existingIndex] = finalExam; } else { newExams = [...currentExams, finalExam]; } updateData({ exams: newExams }); setCurrentView('list'); setEditingExam(null); }; if (currentView === 'builder' && editingExam) { return (

Criador de Provas

Configure os detalhes e as questões da avaliação.

{/* Informações Básicas */}

Informações Básicas

setEditingExam({ ...editingExam, title: e.target.value })} placeholder="Ex: Prova Bimestral de Matemática" 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" />
setEditingExam({ ...editingExam, maxScore: parseFloat(e.target.value) || 0 } as any)} min="0" step="0.1" 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" />
setEditingExam({ ...editingExam, durationMinutes: parseInt(e.target.value) || 0 })} min="0" 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" />

Vincule a uma disciplina do Boletim Escolar para lançar notas automaticamente.

Vincule a um período para que a nota apareça no campo correto do boletim.

{/* Questões */}
{editingExam.questions.map((question, qIndex) => (

{qIndex + 1} Questão

{/* Enunciado */}