import React, { useState, useEffect } from 'react'; import { LayoutDashboard, Users, Briefcase, FileText, Settings, Search, Plus, CheckCircle2, Clock, AlertCircle, Menu, X, Palette, Printer, Trash2, Calculator, ArrowLeft, Edit, Save, AlertTriangle, Archive, Info } from 'lucide-react'; const initialClients = [ { id: 1, name: 'Empresa Alpha', contact: 'Juan Pérez', email: 'juan@alpha.com', phone: '11-2345-6789' }, { id: 2, name: 'Librería El Estudiante', contact: 'María Gómez', email: 'contacto@elestudiante.com', phone: '11-9876-5432' }, { id: 3, name: 'Restaurante Sabores', contact: 'Carlos Ruiz', email: 'info@sabores.com', phone: '11-4567-8901' }, ]; const initialProjects = [ { id: 101, title: 'Rediseño de Logo', clientId: 1, type: 'Diseño', status: 'En Proceso', deadline: '2026-03-20' }, { id: 102, title: 'Impresión Lonas 3x2m', clientId: 2, type: 'Impresión', status: 'Pendiente', deadline: '2026-03-15' }, { id: 103, title: 'Menús QR y Físicos', clientId: 3, type: 'Mixto', status: 'Completado', deadline: '2026-03-10' }, { id: 104, title: 'Tarjetas Personales (x1000)', clientId: 1, type: 'Impresión', status: 'En Proceso', deadline: '2026-03-18' }, ]; const initialQuotes = [ { id: 1001, clientId: 1, description: 'Campaña Redes Sociales', amount: 150000, status: 'Aprobado', date: '2026-03-01', items: [], variables: {} }, { id: 1002, clientId: 2, description: 'Cartelería Vidriera', amount: 85000, status: 'Pendiente', date: '2026-03-11', items: [], variables: {} }, { id: 1003, clientId: 3, description: 'Diseño Packaging', amount: 220000, status: 'Rechazado', date: '2026-02-28', items: [], variables: {} }, ]; const defaultCatalog = [ { id: 'p1', category: 'Perfiles', name: 'Trimcap 20mm', unit: 'ml', price: 4166.67 }, { id: 'p2', category: 'Perfiles', name: 'Perfil Agujereado', unit: 'ml', price: 7916.67 }, { id: 'p3', category: 'Perfiles', name: 'Perfil liso 70mm Aluminio', unit: 'ml', price: 6250.00 }, { id: 'pl1', category: 'Placas', name: 'Acrílico', unit: 'm2', price: 200000.00 }, { id: 'pl2', category: 'Placas', name: 'Policarbonato Clear', unit: 'm2', price: 60000.00 }, { id: 'pl3', category: 'Placas', name: 'PVC 10mm', unit: 'm2', price: 55000.00 }, { id: 'pl4', category: 'Placas', name: 'PVC 3mm', unit: 'm2', price: 40000.00 }, { id: 'pl5', category: 'Placas', name: 'Vinilo Impreso Clear', unit: 'm2', price: 50000.00 }, { id: 'n1', category: 'Iluminación', name: 'Neón flex', unit: 'ml', price: 4000.00 }, { id: 'n2', category: 'Iluminación', name: 'Rollo LED (fracción/m)', unit: 'ml', price: 4700.00 }, { id: 'n3', category: 'Iluminación', name: 'Módulos LED', unit: 'un', price: 1000.00 }, { id: 'f1', category: 'Fuentes', name: 'Fuente 12V 5A', unit: 'un', price: 20000.00 }, { id: 'f2', category: 'Fuentes', name: 'Fuente 12V 10A', unit: 'un', price: 30000.00 }, { id: 'o1', category: 'Otros', name: 'Pegatutti c/ activador 100g', unit: 'un', price: 18000.00 }, ]; const safeGetStorage = (key, initialValue) => { try { if (typeof window !== 'undefined') { const saved = window.localStorage.getItem(key); return saved ? JSON.parse(saved) : initialValue; } } catch (e) { console.warn("LocalStorage bloqueado, usando memoria temporal."); } return initialValue; }; const safeSetStorage = (key, value) => { try { if (typeof window !== 'undefined') { window.localStorage.setItem(key, JSON.stringify(value)); } } catch (e) {} }; // Función Helper Global para generar el número de presupuesto (DDMM-ID-INICIALES) const generateQuoteNumber = (dateString, id, clientName) => { const initials = clientName && clientName !== 'Desconocido' ? clientName.split(' ').map(n => n && n[0]).join('').toUpperCase().substring(0, 2) : ''; if (!dateString) return `0000-${id}${initials ? '-' + initials : ''}`; const [y, m, d] = dateString.split('-'); return `${d}${m}-${id}${initials ? '-' + initials : ''}`; }; // ===================================================================== // SUBCOMPONENTE: COTIZADOR DE CORPÓREOS // ===================================================================== function CotizadorCorporeos({ onBack, quoteId, clients, onSave, requestConfirm, existingQuote, autoPrint }) { const [internalTab, setInternalTab] = useState('cotizador'); const [printMode, setPrintMode] = useState(false); const [catalog, setCatalog] = useState(defaultCatalog); // Datos Generales del Presupuesto const [clientId, setClientId] = useState(existingQuote?.clientId?.toString() || ''); const [date, setDate] = useState(existingQuote?.date || new Date().toISOString().split('T')[0]); const [publicDescription, setPublicDescription] = useState(existingQuote?.description || 'Fabricación de Cartel Corpóreo...'); const currentId = existingQuote ? existingQuote.id : quoteId; const selectedClient = clients.find(c => c.id === Number(clientId)); const clientName = selectedClient ? selectedClient.name : ''; const quoteNumber = generateQuoteNumber(date, currentId, clientName); // Ítems de Materiales const [items, setItems] = useState(existingQuote?.items?.length > 0 ? existingQuote.items : [ { id: 1, description: 'Acrílico', quantity: 3.2, unitPrice: 200000.00 }, { id: 2, description: 'Trimcap 20mm', quantity: 20, unitPrice: 4166.67 }, ]); // Variables y Costos Extra const [variables, setVariables] = useState(existingQuote?.variables && Object.keys(existingQuote.variables).length > 0 ? existingQuote.variables : { horasManoObra: 50, precioHora: 10000, instalacion: 150000, viaticos: 50000, tornillos: 50000, electricidad: 30000, acrilicoLaser: 200000, margenGanancia: 40 }); const [totals, setTotals] = useState({ materiales: 0, fijos: 0, manoObra: 0, costoTotal: 0, ganancia: 0, precioVenta: 0 }); useEffect(() => { const costoMateriales = items.reduce((acc, item) => acc + (item.quantity * item.unitPrice), 0); const costoManoObra = variables.horasManoObra * variables.precioHora; const costoFijos = Number(variables.instalacion) + Number(variables.viaticos) + Number(variables.tornillos) + Number(variables.electricidad) + Number(variables.acrilicoLaser); const costoTotal = costoMateriales + costoManoObra + costoFijos; const ganancia = costoTotal * (variables.margenGanancia / 100); const precioVenta = costoTotal + ganancia; setTotals({ materiales: costoMateriales, manoObra: costoManoObra, fijos: costoFijos, costoTotal: costoTotal, ganancia: ganancia, precioVenta: precioVenta }); }, [items, variables]); useEffect(() => { if (autoPrint && clientId) { handlePrint(); } }, [autoPrint, clientId]); const handleItemChange = (id, field, value) => { setItems(items.map(item => item.id === id ? { ...item, [field]: value } : item)); }; const handleCatalogSelect = (itemId, catalogItemId) => { const selectedProduct = catalog.find(c => c.id === catalogItemId); if (selectedProduct) { setItems(items.map(item => item.id === itemId ? { ...item, description: selectedProduct.name, unitPrice: selectedProduct.price } : item )); } }; const addItem = () => setItems([...items, { id: Date.now(), description: '', quantity: 1, unitPrice: 0 }]); const removeItem = (id) => { if (items.length <= 1) return; requestConfirm('Eliminar Material', '¿Estás seguro de quitar este material del presupuesto?', () => { setItems(prevItems => prevItems.filter(item => item.id !== id)); }); }; const handleVariableChange = (field, value) => { setVariables({ ...variables, [field]: Number(value) || 0 }); }; const handlePrint = () => { if (!clientId) { requestConfirm('Atención', 'Selecciona un cliente antes de imprimir el presupuesto.', null); return; } setPrintMode(true); setTimeout(() => { try { window.print(); } catch (e) { console.log(e); } }, 500); }; const formatCurrency = (val) => '$ ' + Number(val).toLocaleString('es-AR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); if (printMode) { return (

Vista Previa del Documento

Si no se abrió la ventana, presiona Ctrl + P (Windows) o Cmd + P (Mac) en tu teclado.

IG

IDEAGRÁFICA

www.ideagrafica.com.ar

PRESUPUESTO

Nº {quoteNumber}

Fecha: {date ? date.split('-').reverse().join('/') : ''}

Preparado para:

{clientName || 'Cliente No Seleccionado'}

Descripción del Trabajo:

{publicDescription}

Inversión Total

{formatCurrency(totals.precioVenta)}

Los precios no incluyen IVA. Presupuesto válido por 15 días.

Gracias por confiar en Ideagráfica.

Si tiene alguna duda sobre este presupuesto, no dude en contactarnos.

); } return (
IG
IG

IDEAGRÁFICA

www.ideagrafica.com.ar

PRESUPUESTO

Nº {quoteNumber}

{internalTab === 'cotizador' && (
setDate(e.target.value)} className="w-full p-3 bg-slate-50 border border-slate-200 rounded-lg focus:ring-2 focus:ring-indigo-500 font-medium print:bg-transparent print:border-none print:p-0 print:text-lg" />