import React, { useState, useEffect, useMemo } from 'react'; import { Calculator, History, MapPin, Truck, User, Plus, Search, FileText, LogOut, TrendingUp, Fuel, ChevronRight, Save, Trash2, Calendar, AlertCircle, Users, ShieldCheck, UserPlus, XCircle } from 'lucide-react'; import { initializeApp } from 'firebase/app'; import { getFirestore, collection, addDoc, query, onSnapshot, doc, setDoc, deleteDoc, getDoc } from 'firebase/firestore'; import { getAuth, signInWithCustomToken, signInAnonymously, onAuthStateChanged, signOut } from 'firebase/auth'; // --- CONFIGURACIÓN DE FIREBASE --- const firebaseConfig = JSON.parse(__firebase_config); const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); const appId = typeof __app_id !== 'undefined' ? __app_id : 'itd-nicaragua-v1'; const ADMIN_EMAIL = 'armin.romero@itdnicaragua.com'; export default function App() { const [user, setUser] = useState(null); const [isAdmin, setIsAdmin] = useState(false); const [view, setView] = useState('dashboard'); // dashboard, new_offer, list, users const [offers, setOffers] = useState([]); const [authorizedUsers, setAuthorizedUsers] = useState([]); const [loading, setLoading] = useState(false); const [authError, setAuthError] = useState(null); const [newUserEmail, setNewUserEmail] = useState(''); // --- AUTENTICACIÓN --- useEffect(() => { const initAuth = async () => { try { if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(auth, __initial_auth_token); } else { await signInAnonymously(auth); } } catch (err) { setAuthError("Error de autenticación. Verifique la configuración."); } }; initAuth(); const unsubscribe = onAuthStateChanged(auth, (u) => { setUser(u); setIsAdmin(u?.email === ADMIN_EMAIL); }); return () => unsubscribe(); }, []); // --- CARGA DE DATOS --- useEffect(() => { if (!user) return; // Listener de Ofertas const qOffers = collection(db, 'artifacts', appId, 'public', 'data', 'ofertas'); const unsubOffers = onSnapshot(qOffers, (snapshot) => { const data = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); setOffers(data.sort((a, b) => new Date(b.fecha) - new Date(a.fecha))); }); // Listener de Usuarios Autorizados (Solo si es Admin) let unsubUsers = () => {}; if (isAdmin) { const qUsers = collection(db, 'artifacts', appId, 'public', 'data', 'authorized_users'); unsubUsers = onSnapshot(qUsers, (snapshot) => { const data = snapshot.docs.map(doc => ({ email: doc.id, ...doc.data() })); setAuthorizedUsers(data); }); } return () => { unsubOffers(); unsubUsers(); }; }, [user, isAdmin]); // --- ESTADO DEL FORMULARIO --- const [formData, setFormData] = useState({ cliente: '', siglasCliente: '', proyecto: '', tipo: 'carretera', distanciaKm: 0, diasCampo: 1, numVehiculos: 1, precioCombustible: 185.50, rendimiento: 35, movInternaDiaria: 20, precioUnitario: 500, cantidadTrabajo: 1 }); // --- CÁLCULOS --- const calculos = useMemo(() => { const { distanciaKm, diasCampo, numVehiculos, precioCombustible, rendimiento, movInternaDiaria, precioUnitario, cantidadTrabajo } = formData; const galonesTraslado = (distanciaKm * 2) / (rendimiento || 1); const galonesInternos = (movInternaDiaria * diasCampo) / (rendimiento || 1); const totalGalones = (galonesTraslado + galonesInternos) * numVehiculos; const costoLogistica = totalGalones * precioCombustible; const costoTecnico = precioUnitario * cantidadTrabajo; const totalBruto = costoLogistica + costoTecnico; const utilidad = totalBruto * 0.20; const totalFinal = totalBruto + utilidad; return { costoLogistica, costoTecnico, totalFinal, totalGalones }; }, [formData]); // --- ACCIONES --- const handleSaveOffer = async () => { if (!formData.siglasCliente || !formData.proyecto) return; setLoading(true); const d = new Date(); const codigoGenerado = `ITD-${formData.siglasCliente.toUpperCase()}-${String(d.getDate()).padStart(2, '0')}${String(d.getMonth() + 1).padStart(2, '0')}${String(d.getFullYear()).slice(-2)}-${String(offers.length + 1).padStart(2, '0')}`; try { await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'ofertas'), { codigo: codigoGenerado, cliente: formData.cliente, siglas: formData.siglasCliente, proyecto: formData.proyecto, total: calculos.totalFinal, fecha: new Date().toISOString(), detalles: formData, creador: user?.email || 'Anonimo' }); setView('list'); setLoading(false); setFormData({ ...formData, cliente: '', siglasCliente: '', proyecto: '', distanciaKm: 0, cantidadTrabajo: 1 }); } catch (e) { console.error(e); setLoading(false); } }; const handleAuthorizeUser = async () => { if (!newUserEmail || !isAdmin) return; const emailKey = newUserEmail.toLowerCase().trim(); try { await setDoc(doc(db, 'artifacts', appId, 'public', 'data', 'authorized_users', emailKey), { autorizadoPor: ADMIN_EMAIL, fecha: new Date().toISOString(), estado: 'activo' }); setNewUserEmail(''); } catch (e) { console.error(e); } }; const handleRevokeUser = async (email) => { if (!isAdmin || email === ADMIN_EMAIL) return; try { await deleteDoc(doc(db, 'artifacts', appId, 'public', 'data', 'authorized_users', email)); } catch (e) { console.error(e); } }; if (authError) return (

Error del Sistema

{authError}

); return (
{/* Sidebar */} {/* Main Content */}

{view === 'dashboard' && 'Panel de Control'} {view === 'new_offer' && 'Nueva Cotización'} {view === 'list' && 'Historial de Ofertas'} {view === 'users' && 'Gestión de Usuarios'}

{/* Dashboard View */} {view === 'dashboard' && (

Ofertas Totales

{offers.length}

Volumen C$

{offers.reduce((a, c) => a + c.total, 0).toLocaleString()}

Personal Activo

{isAdmin ? authorizedUsers.length : 'Restringido'}

)} {/* User Management View */} {view === 'users' && isAdmin && (

Autorizar Nuevo Correo

setNewUserEmail(e.target.value)} />

Nota: Por seguridad, las contraseñas son privadas y solo el usuario puede verlas/crearlas al registrarse.

{authorizedUsers.map(authU => ( ))}
Usuario (Correo) Estado Fecha Alta Acciones
{authU.email} Activo {new Date(authU.fecha).toLocaleDateString()} {authU.email !== ADMIN_EMAIL && ( )}
)} {/* New Offer View */} {view === 'new_offer' && (

Datos Generales

setFormData({...formData, cliente: e.target.value})} /> setFormData({...formData, siglasCliente: e.target.value})} />