import React, { useState, useEffect } from 'react'; import { Plus, Trash2, Download, Settings, User, Monitor, ClipboardCheck, Stethoscope, Wrench, DollarSign, ShieldCheck, MapPin, Mail, Phone, Loader2, RotateCcw } from 'lucide-react'; const App = () => { const [isGenerating, setIsGenerating] = useState(false); const [isPreview, setIsPreview] = useState(false); const [showResetConfirm, setShowResetConfirm] = useState(false); // Función para crear la estructura base de un nuevo equipo const createNewEquipment = () => ({ id: Date.now() + Math.random(), info: { type: '', brandModel: '', serialNumber: '' }, reception: { hasCharger: false, physicalState: '', password: '' }, diagnosis: { reportedFailure: '', findings: '', hardwareStatus: '', softwareStatus: '' }, works: [{ id: Date.now() + 1, description: '' }], costs: { labor: 0, partsTotal: 0, partsDetails: '' } }); // Datos iniciales para el formulario const getInitialData = () => ({ orderNumber: 'OT-' + Math.floor(Math.random() * 1000000), date: new Date().toLocaleDateString('es-ES', { day: 'numeric', month: 'long', year: 'numeric' }), client: { name: '', id: '', phone: '', email: '' }, equipments: [createNewEquipment()], recommendations: [ { id: 1, description: 'Realizar un mantenimiento preventivo cada 6 meses.' }, { id: 2, description: 'Utilizar un regulador de voltaje o protector de picos.' } ], warrantyDays: 30, technicianName: 'ING. IVÁN BOLAGAY', technicianTitle: 'Gerente General' }); const [data, setData] = useState(getInitialData()); // Carga dinámica de la librería para exportar a PDF useEffect(() => { const script = document.createElement('script'); script.src = 'https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js'; script.async = true; document.body.appendChild(script); return () => { if (document.body.contains(script)) document.body.removeChild(script); }; }, []); const handleGlobalChange = (section, field, value) => { setData(prev => ({ ...prev, [section]: typeof prev[section] === 'object' ? { ...prev[section], [field]: value } : value })); }; const handleEquipChange = (equipId, section, field, value) => { setData(prev => ({ ...prev, equipments: prev.equipments.map(e => { if (e.id !== equipId) return e; return { ...e, [section]: typeof e[section] === 'object' ? { ...e[section], [field]: value } : value }; }) })); }; const addEquipment = () => { setData(prev => ({ ...prev, equipments: [...prev.equipments, createNewEquipment()] })); }; const removeEquipment = (id) => { if (data.equipments.length > 1) { setData(prev => ({ ...prev, equipments: prev.equipments.filter(e => e.id !== id) })); } }; const handleWorkChange = (equipId, workId, value) => { setData(prev => ({ ...prev, equipments: prev.equipments.map(e => { if (e.id !== equipId) return e; return { ...e, works: e.works.map(w => w.id === workId ? { ...w, description: value } : w) }; }) })); }; const addWork = (equipId) => { setData(prev => ({ ...prev, equipments: prev.equipments.map(e => { if (e.id !== equipId) return e; return { ...e, works: [...e.works, { id: Date.now(), description: '' }] }; }) })); }; const removeWork = (equipId, workId) => { setData(prev => ({ ...prev, equipments: prev.equipments.map(e => { if (e.id !== equipId) return e; if (e.works.length <= 1) return e; return { ...e, works: e.works.filter(w => w.id !== workId) }; }) })); }; // Función para resetear el formulario a su estado original const handleResetForm = () => { setData(getInitialData()); setShowResetConfirm(false); setIsPreview(false); }; // Lógica para descargar el documento PDF const handleDownloadPDF = async () => { if (isGenerating) return; const wasPreview = isPreview; if (!wasPreview) setIsPreview(true); setIsGenerating(true); setTimeout(() => { const element = document.getElementById('report-document'); const opt = { margin: [10, 10, 10, 10], filename: `Informe_${data.orderNumber}_${data.client.name.replace(/\s+/g, '_')}.pdf`, image: { type: 'jpeg', quality: 0.98 }, html2canvas: { scale: 2, useCORS: true, letterRendering: true, scrollY: 0 }, jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' } }; if (window.html2pdf) { window.html2pdf().from(element).set(opt).save().then(() => { setIsGenerating(false); if (!wasPreview) setIsPreview(false); }); } else { setIsGenerating(false); } }, 600); }; const totalLabor = data.equipments.reduce((acc, e) => acc + parseFloat(e.costs.labor || 0), 0); const totalParts = data.equipments.reduce((acc, e) => acc + parseFloat(e.costs.partsTotal || 0), 0); const grandTotal = totalLabor + totalParts; return (
{/* Header Interactivo */}
CS

CompuServer Pro

{/* Botón de Limpiar Formulario */} {!isPreview && (
{/* Modal de Confirmación */} {showResetConfirm && (

¿Deseas vaciar todos los campos del formulario?

)}
)}
{!isPreview ? ( /* PESTAÑA DE EDICIÓN (FORMULARIO) */

Identificación de Servicio

handleGlobalChange('orderNumber', null, e.target.value)} className="w-full p-2 bg-slate-50 border-none rounded-lg font-mono font-bold text-blue-700 outline-none focus:ring-1 focus:ring-blue-500" />
handleGlobalChange('date', null, e.target.value)} className="w-full p-2 bg-slate-50 border-none rounded-lg outline-none focus:ring-1 focus:ring-blue-500" />

Información del Cliente

handleGlobalChange('client', 'name', e.target.value)} className="w-full p-2 bg-slate-50 border-none rounded-lg text-sm outline-none focus:ring-1 focus:ring-blue-500" />
handleGlobalChange('client', 'id', e.target.value)} className="w-full p-2 bg-slate-50 border-none rounded-lg text-sm outline-none focus:ring-1 focus:ring-blue-500" /> handleGlobalChange('client', 'phone', e.target.value)} className="w-full p-2 bg-slate-50 border-none rounded-lg text-sm outline-none focus:ring-1 focus:ring-blue-500" />

Equipos Registrados ({data.equipments.length})

{data.equipments.map((equip, index) => (
Equipo #{index + 1} {data.equipments.length > 1 && ( )}

Datos Técnicos

handleEquipChange(equip.id, 'info', 'type', e.target.value)} className="w-full p-2 bg-slate-50 border-none rounded-lg text-sm outline-none focus:ring-1 focus:ring-blue-500" /> handleEquipChange(equip.id, 'info', 'brandModel', e.target.value)} className="w-full p-2 bg-slate-50 border-none rounded-lg text-sm outline-none focus:ring-1 focus:ring-blue-500" /> handleEquipChange(equip.id, 'info', 'serialNumber', e.target.value)} className="w-full p-2 bg-slate-50 border-none rounded-lg text-sm font-mono outline-none focus:ring-1 focus:ring-blue-500" />

Análisis y Trabajos