Refactor manejo de URL para eliminar parámetros de búsqueda en la navegación y mejorar la visibilidad de personas en formularios

This commit is contained in:
Naiel
2026-02-23 12:38:28 +00:00
parent 9ab0472e2a
commit 75947d3468
8 changed files with 133 additions and 22 deletions

View File

@@ -52,7 +52,7 @@ function setUrlHash(hash) {
}
}
window.onhashchange = () => {
open_page(location.hash.replace('#', ''));
open_page(location.hash.replace('#', '').split("?")[0]);
};
function download(filename, text) {

View File

@@ -621,7 +621,8 @@ function addCategory_Personas(
change_cb = () => {},
label = 'Persona',
open_default = false,
default_empty_text = '- Lista Vacia -'
default_empty_text = '- Lista Vacia -',
show_hidden = false,
) {
var details_0 = document.createElement('details'); // children: img_0, summary_0
//details_0.open = true;
@@ -670,6 +671,7 @@ function addCategory_Personas(
.map((entry) => {
var key = entry['_key'];
var value = entry;
if (value.Oculto == true && !show_hidden) { return; }
if (lastreg != value.Region.toUpperCase()) {
lastreg = value.Region.toUpperCase();
var h3_0 = document.createElement('h2');
@@ -1218,6 +1220,7 @@ function TS_IndexElement(
id="${searchKeyInput}"
placeholder="🔍 Buscar..."
style="width: calc(100% - 18px); padding: 8px; border: 1px solid #ccc; border-radius: 4px; background-color: rebeccapurple; color: white;"
value=""
/>
</th>
</tr>
@@ -1237,7 +1240,11 @@ function TS_IndexElement(
// Add search functionality
const searchKeyEl = document.getElementById(searchKeyInput);
searchKeyEl.addEventListener('input', () => debounce(debounce_search, render, 200, [rows]));
// If there is a preset search value in URL, apply it
var hashQuery = new URLSearchParams(window.location.hash.split('?')[1]);
if (hashQuery.has('search')) {
searchKeyEl.value = hashQuery.get('search');
}
function searchInData(data, searchValue, config) {
if (!searchValue) return true;
@@ -1846,7 +1853,7 @@ var BootIntervalID = setInterval(() => {
SUB_LOGGED_IN = true;
localStorage.setItem('TELESEC_BYPASS_ID', SUB_LOGGED_IN_ID);
SetPages();
open_page(location.hash.replace('#', ''));
open_page(location.hash.replace('#', '').split("?")[0]);
}
if (!data) {
const persona = { Nombre: 'Admin (bypass)', Roles: 'ADMIN,' };
@@ -1883,7 +1890,7 @@ var BootIntervalID = setInterval(() => {
}
} else {
SetPages();
open_page(location.hash.replace('#', ''));
open_page(location.hash.replace('#', '').split("?")[0]);
}
clearInterval(BootIntervalID);
}

View File

@@ -82,7 +82,7 @@ if (urlParams.get('couch') != null) {
history.replaceState(
null,
'',
location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : '') + location.hash
location.pathname + (urlParams.toString() ? '?' + urlParams.toString() : '') + location.hash.split("?")[0]
);
console.log('CouchDB auto-configured from URL parameter');

View File

@@ -456,7 +456,7 @@ Cargando...</pre
setUrlHash('index');
return;
}
var item = location.hash.replace('#', '').split(',')[2];
var item = location.hash.replace('#', '').split("?")[0].split(',')[2];
if (!item) {
// No item, show section
switch (section) {

View File

@@ -634,7 +634,7 @@ PAGES.cajas = {
}
// Check for special routes
var parts = location.hash.split(',');
var parts = location.hash.split("?")[0].split(',');
if (parts[2] === 'movimientos' && parts[3] === '_nuevo') {
PAGES.cajas.nuevo_movimiento(parts[1]);
return;

View File

@@ -421,11 +421,11 @@ PAGES.login = {
SUB_LOGGED_IN_DETAILS = SC_Personas[SUB_LOGGED_IN_ID];
SUB_LOGGED_IN = true;
SetPages();
if (location.hash.replace('#', '').startsWith('login')) {
if (location.hash.replace('#', '').split("?")[0].startsWith('login')) {
open_page('index');
setUrlHash('index');
} else {
open_page(location.hash.replace('#', ''));
open_page(location.hash.replace('#', '').split("?")[0]);
}
};

View File

@@ -5,6 +5,78 @@ PAGES.pagos = {
icon: 'static/appico/credit_cards.png',
AccessControl: true,
Title: 'Pagos',
CajaCafeID: 'caja_cafe',
CajaCafeNombre: 'Caja Café',
__getVisiblePersonas: function () {
return Object.fromEntries(
Object.entries(SC_Personas).filter(([_, persona]) => !(persona && persona.Oculto === true))
);
},
__ensureCajaCafePersona: function () {
var cajaId = PAGES.pagos.CajaCafeID;
var cajaNombre = PAGES.pagos.CajaCafeNombre;
var existing = SC_Personas[cajaId];
if (existing && existing.Nombre === cajaNombre && existing.Oculto === true) {
return Promise.resolve(cajaId);
}
var data = {
Nombre: cajaNombre,
Region: 'Sistema',
Roles: '',
SC_Anilla: '',
markdown: 'Monedero interno de cafetería',
Monedero_Balance: parseFloat((existing && existing.Monedero_Balance) || 0) || 0,
Monedero_Notas: (existing && existing.Monedero_Notas) || '',
Oculto: true,
};
return DB.put('personas', cajaId, data)
.then(() => {
SC_Personas[cajaId] = data;
return cajaId;
})
.catch((e) => {
console.warn('DB.put error', e);
return null;
});
},
__creditCajaCafeForGasto: function (personaOrigenId, monto, callback) {
var cajaId = PAGES.pagos.CajaCafeID;
if (personaOrigenId === cajaId) {
if (callback) callback();
return;
}
PAGES.pagos.__ensureCajaCafePersona().then((resolvedCajaId) => {
if (!resolvedCajaId) {
if (callback) callback();
return;
}
var caja = SC_Personas[resolvedCajaId];
if (!caja) {
if (callback) callback();
return;
}
var currentBalance = parseFloat(caja.Monedero_Balance || 0);
caja.Monedero_Balance = fixfloat(currentBalance + monto);
DB.put('personas', resolvedCajaId, caja)
.then(() => {
if (callback) callback();
})
.catch((e) => {
console.warn('DB.put error', e);
if (callback) callback();
});
});
},
// Datafono view for creating/processing transactions
datafono: function (prefilledData = {}) {
@@ -32,6 +104,8 @@ PAGES.pagos = {
sessionStorage.removeItem('pagos_scanned_persona');
}
PAGES.pagos.__ensureCajaCafePersona();
var field_tipo = safeuuid();
var field_monto = safeuuid();
var field_persona = safeuuid();
@@ -413,9 +487,10 @@ PAGES.pagos = {
var container = document.querySelector('#personaSelector');
container.innerHTML = '';
document.getElementById(field_persona).value = selectedPersona;
var visiblePersonas = PAGES.pagos.__getVisiblePersonas();
addCategory_Personas(
container,
SC_Personas,
visiblePersonas,
selectedPersona,
(personaId) => {
document.getElementById(field_persona).value = personaId;
@@ -431,9 +506,10 @@ PAGES.pagos = {
var container = document.querySelector('#personaDestinoSelector');
container.innerHTML = '';
document.getElementById(field_persona_destino).value = selectedPersonaDestino;
var visiblePersonas = PAGES.pagos.__getVisiblePersonas();
addCategory_Personas(
container,
SC_Personas,
visiblePersonas,
selectedPersonaDestino,
(personaId) => {
document.getElementById(field_persona_destino).value = personaId;
@@ -498,20 +574,30 @@ PAGES.pagos = {
// Don't update balance for Efectivo Gastos (paying with cash)
var shouldUpdateBalance = !(tipo === 'Gasto' && metodo === 'Efectivo');
if (shouldUpdateBalance) {
updateWalletBalance(personaId, tipo, monto, () => {
if (tipo === 'Transferencia') {
var destinoId = transactionData.PersonaDestino;
updateWalletBalance(destinoId, 'Ingreso', monto, () => {
function finalizeTransactionSave() {
if (tipo === 'Gasto') {
PAGES.pagos.__creditCajaCafeForGasto(personaId, monto, () => {
saveTransaction(ticketId, transactionData);
});
} else {
saveTransaction(ticketId, transactionData);
}
}
if (shouldUpdateBalance) {
updateWalletBalance(personaId, tipo, monto, () => {
if (tipo === 'Transferencia') {
var destinoId = transactionData.PersonaDestino;
updateWalletBalance(destinoId, 'Ingreso', monto, () => {
finalizeTransactionSave();
});
} else {
finalizeTransactionSave();
}
});
} else {
// Skip balance update for Efectivo Gastos
saveTransaction(ticketId, transactionData);
finalizeTransactionSave();
}
}
@@ -666,7 +752,7 @@ PAGES.pagos = {
return;
}
var tid = ftid.split(',')[0];
var tid2 = location.hash.split(',');
var tid2 = location.hash.split("?")[0].split(',');
if (tid == 'datafono') {
PAGES.pagos.datafono();
return;
@@ -929,7 +1015,14 @@ PAGES.pagos = {
});
} else if (tipo === 'Gasto') {
revertWalletBalance(personaId, 'Ingreso', monto, () => {
var cajaId = PAGES.pagos.CajaCafeID;
if (personaId === cajaId) {
deleteTransaction(tid);
return;
}
revertWalletBalance(cajaId, 'Gasto', monto, () => {
deleteTransaction(tid);
});
});
} else if (tipo === 'Transferencia') {
var destinoId = data.PersonaDestino;
@@ -994,6 +1087,8 @@ PAGES.pagos = {
return;
}
PAGES.pagos.__ensureCajaCafePersona();
var btn_datafono = safeuuid();
var total_ingresos = safeuuid();
var total_gastos = safeuuid();
@@ -1276,6 +1371,8 @@ PAGES.pagos = {
return;
}
PAGES.pagos.__ensureCajaCafePersona();
var field_tipo = safeuuid();
var field_monto = safeuuid();
var field_persona = safeuuid();
@@ -1440,9 +1537,10 @@ PAGES.pagos = {
var container = document.querySelector('#personaSelector');
container.innerHTML = '';
document.getElementById(field_persona).value = selectedPersona;
var visiblePersonas = PAGES.pagos.__getVisiblePersonas();
addCategory_Personas(
container,
SC_Personas,
visiblePersonas,
selectedPersona,
(personaId) => {
document.getElementById(field_persona).value = personaId;
@@ -1458,9 +1556,10 @@ PAGES.pagos = {
var container = document.querySelector('#personaDestinoSelector');
container.innerHTML = '';
document.getElementById(field_persona_destino).value = selectedPersonaDestino;
var visiblePersonas = PAGES.pagos.__getVisiblePersonas();
addCategory_Personas(
container,
SC_Personas,
visiblePersonas,
selectedPersonaDestino,
(personaId) => {
document.getElementById(field_persona_destino).value = personaId;

View File

@@ -17,6 +17,7 @@ PAGES.personas = {
var field_notas = safeuuid();
var field_anilla = safeuuid();
var field_foto = safeuuid();
var field_oculto = safeuuid();
var render_foto = safeuuid();
var field_monedero_balance = safeuuid();
var field_monedero_notas = safeuuid();
@@ -35,7 +36,6 @@ PAGES.personas = {
Zona<br>
<input type="text" id="${field_zona}"><br><br>
</label>
</label>
<details>
<summary>Permisos</summary>
<form id="${permisosdet}">
@@ -50,7 +50,10 @@ PAGES.personas = {
<img id="${render_foto}" height="100px" style="border: 3px inset; min-width: 7px;" src="static/ico/user_generic.png">
<input type="file" accept="image/*" id="${field_foto}" style="display: none;"><br><br>
</label>
<label>
Ocultar persona?<br>
<input type="checkbox" id="${field_oculto}"><br><br>
</label>
<details style="background: #e3f2fd; border: 2px solid #2196f3; border-radius: 8px; padding: 10px; margin: 15px 0;">
<summary style="cursor: pointer; font-weight: bold; color: #1976d2;">💳 Tarjeta Monedero</summary>
<div style="padding: 15px;">
@@ -110,6 +113,7 @@ PAGES.personas = {
document.getElementById(field_nombre).value = data['Nombre'] || '';
document.getElementById(field_zona).value = data['Region'] || '';
document.getElementById(field_anilla).value = data['SC_Anilla'] || '';
document.getElementById(field_oculto).checked = data['Oculto'] || false;
// set fallback image immediately
document.getElementById(render_foto).src = data['Foto'] || 'static/ico/user_generic.png';
resized = data['Foto'] || 'static/ico/user_generic.png';
@@ -166,6 +170,7 @@ PAGES.personas = {
Region: document.getElementById(field_zona).value,
Roles: dt.getAll('perm').join(',') + ',',
SC_Anilla: document.getElementById(field_anilla).value,
Oculto: document.getElementById(field_oculto).checked,
// Foto moved to PouchDB attachment named 'foto'
markdown: document.getElementById(field_notas).value,
Monedero_Balance: parseFloat(document.getElementById(field_monedero_balance).value) || 0,
@@ -204,7 +209,7 @@ PAGES.personas = {
});
};
document.getElementById(btn_ver_monedero).onclick = () => {
setUrlHash('pagos'); // Navigate to pagos and show transactions for this person
setUrlHash('pagos?search=' + encodeURIComponent(document.getElementById(field_nombre).value)); // Navigate to pagos and show transactions for this person
};
document.getElementById(btn_borrar).onclick = () => {
if (confirm('¿Quieres borrar esta persona?') == true) {