import React, { useState, useEffect, useRef } from 'react'; import { LayoutDashboard, FileText, Users, Settings, LogOut, Plus, Search, Filter, AlertCircle, CheckCircle2, Clock, ChevronRight, PenTool, Download, UserCircle, Menu, X, Bell, Activity } from 'lucide-react'; // ========================================== // 1. MOCK DATA & SCHEMAS (Simulando MySQL DB) // ========================================== const MOCK_USERS = [ { id: 1, name: 'Hna. Helen Gomez', role: 'TUTOR', email: 'helen@mundoabc.edu', avatar: 'HG' }, { id: 2, name: 'Admin Principal', role: 'ADMIN', email: 'admin@mundoabc.edu', avatar: 'AD' }, { id: 3, name: 'Carlos Cardales', role: 'PADRE', email: 'padre@correo.com', avatar: 'CC' }, { id: 4, name: 'Yeiber Cardales', role: 'ESTUDIANTE', email: 'yeiber@mundoabc.edu', avatar: 'YC', grade: '6º', tutorId: 1 }, { id: 5, name: 'Director Académico', role: 'DIRECTOR', email: 'director@mundoabc.edu', avatar: 'DA' }, ]; const INFRACTION_TYPES = [ 'Muestra conducta agresiva', 'Falta de respeto a compañeros o tutores', 'Traer objetos no permitidos al aula', 'No cumplió las normas de convivencia establecidas', 'Uso indebido de dispositivos electrónicos durante actividades académicas', 'No cumple con las normas en el aula' ]; let initialIncidents = [ { id: 'INC-2026-001', studentId: 4, tutorId: 1, date: '2026-05-13', infractions: ['No cumple con las normas en el aula', 'Uso indebido de dispositivos electrónicos durante actividades académicas'], description: 'El estudiante ha presentado problemas de conducta dentro del aula.', status: 'PENDIENTE_FIRMAS', // PENDIENTE_FIRMAS, CERRADO, EN_REVISION agreements: 'El estudiante se compromete a prestar atención. Los padres supervisarán su comportamiento.', signatures: { tutor: { signed: true, date: '2026-05-13', data: 'mock-signature-data' }, padre: { signed: false, date: null, data: null }, estudiante: { signed: false, date: null, data: null }, director: { signed: false, date: null, data: null } } } ]; // ========================================== // 2. COMPONENTES UI REUTILIZABLES // ========================================== const Badge = ({ children, variant = 'gray' }) => { const variants = { gray: 'bg-gray-100 text-gray-800', blue: 'bg-blue-100 text-blue-800', yellow: 'bg-yellow-100 text-yellow-800', red: 'bg-red-100 text-red-800', green: 'bg-green-100 text-green-800', }; return ( {children} ); }; const Button = ({ children, onClick, variant = 'primary', className = '', icon: Icon, type="button" }) => { const baseStyle = "inline-flex items-center justify-center px-4 py-2 border rounded-md shadow-sm text-sm font-medium focus:outline-none focus:ring-2 focus:ring-offset-2 transition-colors"; const variants = { primary: "border-transparent text-white bg-blue-600 hover:bg-blue-700 focus:ring-blue-500", secondary: "border-gray-300 text-gray-700 bg-white hover:bg-gray-50 focus:ring-blue-500", danger: "border-transparent text-white bg-red-600 hover:bg-red-700 focus:ring-red-500", }; return ( ); }; // ========================================== // 3. COMPONENTE FIRMA DIGITAL (Canvas) // ========================================== const SignaturePad = ({ onSave, onCancel, roleToSign }) => { const canvasRef = useRef(null); const [isDrawing, setIsDrawing] = useState(false); useEffect(() => { const canvas = canvasRef.current; if (canvas) { const ctx = canvas.getContext('2d'); ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.strokeStyle = '#0f172a'; // Slate 900 // Fix resolution for high DPI displays const rect = canvas.getBoundingClientRect(); canvas.width = rect.width * 2; canvas.height = rect.height * 2; ctx.scale(2, 2); } }, []); const getCoordinates = (e) => { const canvas = canvasRef.current; const rect = canvas.getBoundingClientRect(); if (e.touches && e.touches.length > 0) { return { x: e.touches[0].clientX - rect.left, y: e.touches[0].clientY - rect.top }; } return { x: e.clientX - rect.left, y: e.clientY - rect.top }; }; const startDrawing = (e) => { e.preventDefault(); const { x, y } = getCoordinates(e); const ctx = canvasRef.current.getContext('2d'); ctx.beginPath(); ctx.moveTo(x, y); setIsDrawing(true); }; const draw = (e) => { e.preventDefault(); if (!isDrawing) return; const { x, y } = getCoordinates(e); const ctx = canvasRef.current.getContext('2d'); ctx.lineTo(x, y); ctx.stroke(); }; const stopDrawing = () => { setIsDrawing(false); }; const handleClear = () => { const canvas = canvasRef.current; const ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); }; const handleSave = () => { const dataUrl = canvasRef.current.toDataURL('image/png'); // Basic check to see if canvas is empty (simplified) onSave(dataUrl, roleToSign); }; return (

Firma Digital - {roleToSign}

Por favor, dibuje su firma en el recuadro inferior usando su mouse o pantalla táctil.

Área de firma
); }; // ========================================== // 4. VISTAS PRINCIPALES // ========================================== const DashboardView = ({ incidents, role }) => { const pending = incidents.filter(i => i.status === 'PENDIENTE_FIRMAS').length; const closed = incidents.filter(i => i.status === 'CERRADO').length; return (

Panel de Control

{/* KPI Cards */}

Total Incidencias

{incidents.length}

Pendientes de Firma

{pending}

Casos Cerrados

{closed}

{/* Gráfico de Estadísticas (NUEVO) */}

Estadísticas de Incidencias por Mes

{/* Barras simuladas */} {[4, 7, 3, 8, 2, 5, 9, 4, 6, 10, 5, 8].map((val, idx) => (
{val} Casos
Mes {idx+1}
))}
{/* Actividad Reciente */}

Incidencias Recientes

{incidents.slice(0, 5).map(inc => { const student = MOCK_USERS.find(u => u.id === inc.studentId); return (
{inc.status === 'CERRADO' ? : }

{inc.id} - {student?.name}

{inc.description}

{inc.date} {inc.status.replace('_', ' ')}
); })}
); }; const CreateIncidentView = ({ onSubmit, onCancel }) => { const [formData, setFormData] = useState({ studentId: '', date: new Date().toISOString().split('T')[0], infractions: [], description: '', agreements: '' }); const students = MOCK_USERS.filter(u => u.role === 'ESTUDIANTE'); const toggleInfraction = (infraction) => { setFormData(prev => ({ ...prev, infractions: prev.infractions.includes(infraction) ? prev.infractions.filter(i => i !== infraction) : [...prev.infractions, infraction] })); }; const handleSubmit = (e) => { e.preventDefault(); onSubmit(formData); }; return (

Registrar Nueva Incidencia

{/* Header del formulario imitando la imagen */}
ABC

INCIDENCIA ESCOLAR

Mundo ABC - Reporte Oficial

setFormData({...formData, date: e.target.value})} className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm" />
{/* Datos del Estudiante */}

1. Datos del Estudiante

s.id === formData.studentId)?.grade : ''} className="block w-full rounded-md border-gray-200 bg-gray-100 shadow-sm sm:text-sm cursor-not-allowed" placeholder="Se autocompleta..." />
{/* Situación */}

Situación Reportada

{INFRACTION_TYPES.map((infraction, idx) => ( ))}
{/* Descripción */}

Descripción Detallada