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
Nota: Por seguridad, las contraseñas son privadas y solo el usuario puede verlas/crearlas al registrarse.
| Usuario (Correo) |
Estado |
Fecha Alta |
Acciones |
{authorizedUsers.map(authU => (
| {authU.email} |
Activo
|
{new Date(authU.fecha).toLocaleDateString()} |
{authU.email !== ADMIN_EMAIL && (
)}
|
))}
)}
{/* New Offer View */}
{view === 'new_offer' && (
Cotización
C$ {calculos.totalFinal.toLocaleString(undefined, {maximumFractionDigits: 0})}
)}
{/* List View */}
{view === 'list' && (
| Código |
Cliente |
Monto |
{isAdmin && Acciones | }
{offers.map(o => (
| {o.codigo} |
{o.siglas} |
C$ {o.total.toLocaleString()} |
{isAdmin && (
|
)}
))}
)}
);
}