1ra Versión

This commit is contained in:
MarcosFlorSalcedo
2026-07-14 18:24:27 -03:00
commit 8ec55e40fc
86 changed files with 15839 additions and 0 deletions
+291
View File
@@ -0,0 +1,291 @@
let gastosActuales = {};
let columnasGastos = []; // Columnas dinámicas de gastos
document.addEventListener('DOMContentLoaded', () => {
cargarEstructuraGastos();
setupFormListeners();
});
function setupFormListeners() {
// Formulario para agregar nuevo tipo de gasto
const formAgregarTipo = document.getElementById('form-agregar-tipo-gasto');
if (formAgregarTipo) {
formAgregarTipo.addEventListener('submit', handleAgregarTipoGasto);
}
}
// ========== CARGAR ESTRUCTURA DINÁMICA ==========
async function cargarEstructuraGastos() {
try {
const response = await fetch('../php/Obtener_Gastos.php');
const data = await response.json();
if (data.success) {
columnasGastos = data.columnas || [];
gastosActuales = data.gasto || {};
construirFormularioDinamico();
} else {
console.log('No hay gastos registrados:', data.message);
columnasGastos = [];
construirFormularioDinamico();
}
} catch (error) {
console.error('Error al cargar gastos:', error);
}
}
// ========== CONSTRUIR FORMULARIO DINÁMICO ==========
function construirFormularioDinamico() {
// Solo mostrar tabla de gastos
mostrarTablaGastos();
}
// ========== AGREGAR NUEVO TIPO DE GASTO ==========
async function handleAgregarTipoGasto(e) {
e.preventDefault();
const nombre = document.getElementById('nombre-nuevo-gasto').value.trim();
const monto = parseFloat(document.getElementById('monto-nuevo-gasto').value);
if (!nombre || monto < 0) {
alert('Por favor completa los datos correctamente');
return;
}
// Validar nombre (solo letras y espacios)
if (!/^[a-zA-Z\s]+$/.test(nombre)) {
alert('El nombre del gasto solo puede contener letras y espacios');
return;
}
try {
const response = await fetch('../php/Registrar_Gastos.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
nuevo_gasto: nombre,
monto: monto
})
});
const data = await response.json();
if (data.success) {
alert('Nuevo tipo de gasto agregado correctamente');
document.getElementById('form-agregar-tipo-gasto').reset();
cargarEstructuraGastos();
} else {
alert('Error al agregar gasto: ' + data.message);
}
} catch (error) {
console.error('Error:', error);
alert('Error de conexión');
}
}
// ========== MOSTRAR TABLA DE GASTOS ==========
function mostrarTablaGastos() {
const tabla = document.getElementById('tabla-gastos');
if (!tabla) return;
const tbody = tabla.querySelector('tbody');
tbody.innerHTML = '';
if (columnasGastos.length === 0) {
const tr = document.createElement('tr');
const td = document.createElement('td');
td.colSpan = 3;
td.textContent = 'No hay gastos configurados';
td.style.textAlign = 'center';
td.style.color = '#999';
tr.appendChild(td);
tbody.appendChild(tr);
return;
}
columnasGastos.forEach(columna => {
const tr = document.createElement('tr');
const monto = gastosActuales[columna] || 0;
const descripcionFormato = columna.charAt(0).toUpperCase() + columna.slice(1);
// Descripción
const tdDesc = document.createElement('td');
tdDesc.textContent = descripcionFormato;
tr.appendChild(tdDesc);
// Monto
const tdMonto = document.createElement('td');
tdMonto.textContent = `$${parseFloat(monto).toFixed(2)}`;
tr.appendChild(tdMonto);
// Acciones
const tdAcciones = document.createElement('td');
tdAcciones.style.display = 'flex';
tdAcciones.style.gap = '10px';
// Botón Editar
const btnEditar = document.createElement('button');
btnEditar.type = 'button';
btnEditar.className = 'btn-editar-gasto';
btnEditar.textContent = 'Editar';
btnEditar.addEventListener('click', () => activarEdicionGasto(btnEditar, columna));
tdAcciones.appendChild(btnEditar);
// Botón Eliminar
const btnEliminar = document.createElement('button');
btnEliminar.type = 'button';
btnEliminar.className = 'btn-eliminar-gasto';
btnEliminar.textContent = 'Eliminar';
btnEliminar.addEventListener('click', () => abrirModalEliminar(columna));
tdAcciones.appendChild(btnEliminar);
tr.appendChild(tdAcciones);
tbody.appendChild(tr);
});
}
// ========== EDITAR GASTO ==========
function activarEdicionGasto(btnEditar, columnaActual) {
const fila = btnEditar.closest('tr');
const celdas = fila.querySelectorAll('td');
const descripcionActual = celdas[0].textContent;
const montoActual = parseFloat(celdas[1].textContent.replace('$', ''));
// Convertir descripción a input
celdas[0].innerHTML = `<input type="text" value="${columnaActual}" class="input-descripcion-gasto">`;
// Convertir monto a input
celdas[1].innerHTML = `<input type="number" value="${montoActual}" step="0.01" min="0" class="input-monto-gasto">`;
// Crear botones Guardar y Cancelar
const btnGuardar = document.createElement('button');
btnGuardar.type = 'button';
btnGuardar.textContent = 'Guardar';
btnGuardar.className = 'btn-guardar';
btnGuardar.addEventListener('click', () => guardarEdicionGasto(fila, columnaActual, montoActual, descripcionActual));
const btnCancelar = document.createElement('button');
btnCancelar.type = 'button';
btnCancelar.textContent = 'Cancelar';
btnCancelar.className = 'btn-cancelar';
btnCancelar.addEventListener('click', () => cancelarEdicionGasto(fila, columnaActual, montoActual, descripcionActual));
// Reemplazar botones en la celda de acciones
celdas[2].innerHTML = '';
celdas[2].appendChild(btnGuardar);
celdas[2].appendChild(btnCancelar);
}
function cancelarEdicionGasto(fila, columnaActual, montoActual, descripcionActual) {
const celdas = fila.querySelectorAll('td');
// Restaurar descripción
celdas[0].textContent = descripcionActual;
// Restaurar monto
celdas[1].textContent = `$${parseFloat(montoActual).toFixed(2)}`;
// Restaurar botones Editar y Eliminar
const btnEditar = document.createElement('button');
btnEditar.type = 'button';
btnEditar.className = 'btn-editar-gasto';
btnEditar.textContent = 'Editar';
btnEditar.addEventListener('click', () => activarEdicionGasto(btnEditar, columnaActual));
const btnEliminar = document.createElement('button');
btnEliminar.type = 'button';
btnEliminar.className = 'btn-eliminar-gasto';
btnEliminar.textContent = 'Eliminar';
btnEliminar.addEventListener('click', () => abrirModalEliminar(columnaActual));
celdas[2].innerHTML = '';
celdas[2].appendChild(btnEditar);
celdas[2].appendChild(btnEliminar);
}
async function guardarEdicionGasto(fila, columnaActual, montoActual, descripcionActual) {
const nuevoNombre = fila.querySelector('.input-descripcion-gasto').value.trim();
const nuevoMonto = parseFloat(fila.querySelector('.input-monto-gasto').value);
if (!nuevoNombre) {
alert('El nombre no puede estar vacío');
return;
}
if (isNaN(nuevoMonto) || nuevoMonto < 0) {
alert('El monto debe ser un número válido y mayor o igual a 0');
return;
}
try {
const response = await fetch('../php/Editar_Gasto.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
columna_actual: columnaActual,
columna_nueva: nuevoNombre,
monto: nuevoMonto
})
});
const data = await response.json();
if (data.success) {
alert('Gasto editado correctamente');
cargarEstructuraGastos();
} else {
alert('Error al editar gasto: ' + data.message);
cancelarEdicionGasto(fila, columnaActual, montoActual, descripcionActual);
}
} catch (error) {
console.error('Error:', error);
alert('Error de conexión');
cancelarEdicionGasto(fila, columnaActual, montoActual, descripcionActual);
}
}
// ========== ELIMINAR GASTO ==========
function abrirModalEliminar(columna) {
const confirmar = confirm(`¿Deseas eliminar el gasto "${columna}"? Esta acción no se puede deshacer.`);
if (confirmar) {
eliminarGasto(columna);
}
}
async function eliminarGasto(columna) {
try {
const response = await fetch('../php/Eliminar_Gasto.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
columna: columna
})
});
const data = await response.json();
if (data.success) {
alert('Gasto eliminado correctamente');
cargarEstructuraGastos();
} else {
alert('Error al eliminar gasto: ' + data.message);
}
} catch (error) {
console.error('Error:', error);
alert('Error de conexión');
}
}