diff --git a/src/app_modules.js b/src/app_modules.js index 13e5ff4..a03d377 100644 --- a/src/app_modules.js +++ b/src/app_modules.js @@ -768,281 +768,240 @@ function TS_IndexElement( return false; } - function render() { - function sorter(a, b) { - // If both items have Fecha field, sort by date first - if (a.Fecha && b.Fecha) { - // Primary sort by date - if (a.Fecha < b.Fecha) return -1; - if (a.Fecha > b.Fecha) return 1; - - // Secondary sort by Nombre if dates are equal and both have names - if (a.Nombre && b.Nombre) { - const nameA = a.Nombre.toLowerCase(); - const nameB = b.Nombre.toLowerCase(); - if (nameA < nameB) return -1; - if (nameA > nameB) return 1; - } - return 0; - } - // If persona field exists, sort by Region, then by Nombre - if (a.Persona && b.Persona) { - console.log(a.Persona, SC_Personas[a.Persona]) - const personaA = SC_Personas[a.Persona] || { Nombre: "", Region: "" }; - const personaB = SC_Personas[b.Persona] || { Nombre: "", Region: "" }; - if (personaA.Region < personaB.Region) return -1; - if (personaA.Region > personaB.Region) return 1; - if (personaA.Nombre < personaB.Nombre) return -1; - if (personaA.Nombre > personaB.Nombre) return 1; - return 0; - } - // If no Fecha field exists, sort only by Nombre + // --- Optimized render function --- + let lastSearchValue = ""; + let lastFilteredSorted = []; + function sorter(a, b) { + if (a.Fecha && b.Fecha) { + if (a.Fecha < b.Fecha) return -1; + if (a.Fecha > b.Fecha) return 1; if (a.Nombre && b.Nombre) { const nameA = a.Nombre.toLowerCase(); const nameB = b.Nombre.toLowerCase(); if (nameA < nameB) return -1; if (nameA > nameB) return 1; - return 0; } - return 0; } - - const searchValue = searchKeyEl.value.toLowerCase().trim(); - tablebody_EL.innerHTML = ""; - Object.entries(rows) + if (a.Persona && b.Persona) { + const personaA = SC_Personas[a.Persona] || { Nombre: "", Region: "" }; + const personaB = SC_Personas[b.Persona] || { Nombre: "", Region: "" }; + if (personaA.Region < personaB.Region) return -1; + if (personaA.Region > personaB.Region) return 1; + if (personaA.Nombre < personaB.Nombre) return -1; + if (personaA.Nombre > personaB.Nombre) return 1; + return 0; + } + if (a.Nombre && b.Nombre) { + const nameA = a.Nombre.toLowerCase(); + const nameB = b.Nombre.toLowerCase(); + if (nameA < nameB) return -1; + if (nameA > nameB) return 1; + return 0; + } + return 0; + } + + function getFilteredSortedRows(searchValue) { + // Only use cache if searchValue is not empty and cache is valid + if (searchValue && searchValue === lastSearchValue && lastFilteredSorted.length > 0) { + return lastFilteredSorted; + } + const filtered = Object.entries(rows) .filter(([_, data]) => searchInData(data, searchValue, config)) .map(([_, data]) => data) - .sort(sorter) - .forEach((data) => { - var new_tr = document.createElement("tr"); - - if (canAddCallback != undefined) { - if (canAddCallback(data) == true) { - return; + .sort(sorter); + lastSearchValue = searchValue; + lastFilteredSorted = filtered; + return filtered; + } + + function render() { + const searchValue = searchKeyEl.value.toLowerCase().trim(); + // Use document fragment for batch DOM update + const fragment = document.createDocumentFragment(); + const filteredSorted = getFilteredSortedRows(searchValue); + for (let i = 0; i < filteredSorted.length; i++) { + const data = filteredSorted[i]; + if (canAddCallback != undefined && canAddCallback(data) === true) { + continue; + } + const new_tr = document.createElement("tr"); + if (rowCallback != undefined) { + rowCallback(data, new_tr); + } + config.forEach((key) => { + switch (key.type) { + case "raw": + case "text": { + const tdRaw = document.createElement("td"); + const rawContent = (String(data[key.key]) || key.default || "").replace(/\n/g, "
"); + tdRaw.innerHTML = rawContent; + new_tr.appendChild(tdRaw); + break; } - } - tablebody_EL.append(new_tr); - if (rowCallback != undefined) { - rowCallback(data, new_tr); - } - config.forEach((key) => { - switch (key.type) { - case "raw": - case "text": - const tdRaw = document.createElement("td"); - const rawContent = (String(data[key.key]) || key.default || "").replace( - /\n/g, - "
" - ); - tdRaw.innerHTML = rawContent; - new_tr.appendChild(tdRaw); - break; - case "fecha": - case "fecha-iso": - const tdFechaISO = document.createElement("td"); - if (data[key.key]) { - const fechaArray = data[key.key].split("-"); - tdFechaISO.innerText = fechaArray[2] + "/" + fechaArray[1] + "/" + fechaArray[0]; + case "fecha": + case "fecha-iso": { + const tdFechaISO = document.createElement("td"); + if (data[key.key]) { + const fechaArray = data[key.key].split("-"); + tdFechaISO.innerText = fechaArray[2] + "/" + fechaArray[1] + "/" + fechaArray[0]; + } + new_tr.appendChild(tdFechaISO); + break; + } + case "template": { + const tdCustomTemplate = document.createElement("td"); + new_tr.appendChild(tdCustomTemplate); + key.template(data, tdCustomTemplate); + break; + } + case "comanda": { + const tdComanda = document.createElement("td"); + tdComanda.style.verticalAlign = "top"; + const parsedComanda = JSON.parse(data.Comanda); + const precio = SC_priceCalc(parsedComanda)[0]; + const tempDiv = document.createElement("div"); + tempDiv.innerHTML = setLayeredImages(parsedComanda, data._key); + tdComanda.appendChild(tempDiv.firstChild); + const pre = document.createElement("pre"); + pre.style.fontSize = "15px"; + pre.style.display = "inline-block"; + pre.style.margin = "0"; + pre.style.verticalAlign = "top"; + pre.style.padding = "5px"; + pre.style.background = "rgba(255, 255, 0, 0.5)"; + pre.style.border = "1px solid rgba(0, 0, 0, 0.2)"; + pre.style.borderRadius = "5px"; + pre.style.boxShadow = "2px 2px 5px rgba(0, 0, 0, 0.1)"; + pre.style.height = "100%"; + const spanPrecio = document.createElement("span"); + spanPrecio.style.fontSize = "20px"; + spanPrecio.innerHTML = SC_Personas[data.Persona].Puntos >= 10 ? `Total: Gratis!(${precio}c)` : `Total: ${precio}c`; + pre.innerHTML = "Ticket de compra "; + pre.appendChild(document.createTextNode("\n")); + pre.innerHTML += SC_parse_short(parsedComanda) + "
" + data.Notas + "
"; + pre.appendChild(spanPrecio); + tdComanda.appendChild(pre); + new_tr.appendChild(tdComanda); + break; + } + case "comanda-status": { + var sc_nobtn = ""; + if (urlParams.get("sc_nobtn") == "yes") { + sc_nobtn = "pointer-events: none; opacity: 0.5"; + } + const td = document.createElement("td"); + td.style.fontSize = "17px"; + if (sc_nobtn) { + td.style.pointerEvents = "none"; + td.style.opacity = "0.5"; + } + const createButton = (text, state) => { + const button = document.createElement("button"); + button.textContent = text; + if (data.Estado === state) { + button.className = "rojo"; } - new_tr.appendChild(tdFechaISO); - break; - case "template": - const tdCustomTemplate = document.createElement("td"); - new_tr.appendChild(tdCustomTemplate); - key.template(data, tdCustomTemplate); - break; - case "comanda": - const tdComanda = document.createElement("td"); - tdComanda.style.verticalAlign = "top"; - const parsedComanda = JSON.parse(data.Comanda); - const precio = SC_priceCalc(parsedComanda)[0]; - - // Create a temporary div to parse the HTML from setLayeredImages - const tempDiv = document.createElement("div"); - tempDiv.innerHTML = setLayeredImages(parsedComanda, data._key); - tdComanda.appendChild(tempDiv.firstChild); - - const pre = document.createElement("pre"); - pre.style.fontSize = "15px"; - pre.style.display = "inline-block"; - pre.style.margin = "0"; - pre.style.verticalAlign = "top"; - pre.style.padding = "5px"; - //looking like a post-it - pre.style.background = "rgba(255, 255, 0, 0.5)"; - pre.style.border = "1px solid rgba(0, 0, 0, 0.2)"; - pre.style.borderRadius = "5px"; - pre.style.boxShadow = "2px 2px 5px rgba(0, 0, 0, 0.1)"; - pre.style.height = "100%"; - const spanPrecio = document.createElement("span"); - spanPrecio.style.fontSize = "20px"; - spanPrecio.innerHTML = - SC_Personas[data.Persona].Puntos >= 10 ? - `Total: Gratis!(${precio}c)` : - `Total: ${precio}c`; - pre.innerHTML = "Ticket de compra "; - pre.appendChild(document.createTextNode("\n")); - pre.innerHTML += - SC_parse_short(parsedComanda) + "
" + data.Notas + "
"; - pre.appendChild(spanPrecio); - - tdComanda.appendChild(pre); - new_tr.appendChild(tdComanda); - break; - case "comanda-status": - var sc_nobtn = ""; - if (urlParams.get("sc_nobtn") == "yes") { - sc_nobtn = "pointer-events: none; opacity: 0.5"; - } - const td = document.createElement("td"); - td.style.fontSize = "17px"; - if (sc_nobtn) { - td.style.pointerEvents = "none"; - td.style.opacity = "0.5"; - } - - // Create buttons - const createButton = (text, state) => { - const button = document.createElement("button"); - button.textContent = text; - if (data.Estado === state) { - button.className = "rojo"; - } - button.onclick = (event) => { - event.preventDefault(); - event.stopPropagation(); - data.Estado = state; - var enc = TS_encrypt(data, SECRET, (encrypted) => { - betterGunPut(ref.get(data._key), encrypted); - toastr.success("Guardado!"); - }); - return false; - }; - return button; - }; - - // Create all buttons - const buttons = [ - createButton("Pedido", "Pedido"), - createButton("En preparación", "En preparación"), - createButton("Listo", "Listo"), - createButton("Entregado", "Entregado"), - createButton("Deuda", "Deuda"), - ]; - - // Create paid button separately due to different behavior - const paidButton = document.createElement("button"); - paidButton.textContent = "Pagado"; - paidButton.onclick = (event) => { + button.onclick = (event) => { event.preventDefault(); event.stopPropagation(); - if ( - !confirm( - "¿Quieres marcar como pagado? - Se borrara la comanda y se actualizarán los puntos." - ) - ) { - return false; - } - data.Estado = "Pagado"; - betterGunPut(ref.get(data._key), null); - toastr.success("Guardado!"); - if (SC_Personas[data.Persona].Puntos >= 10 && confirm("¿Pagar con Puntos? - Cancela para pagar con Efectivo.")) { - SC_Personas[data.Persona].Puntos = parseInt(SC_Personas[data.Persona].Puntos) - 10; - toastr.success( - "¡Comada gratis para " + - SC_Personas[data.Persona].Nombre + - "!" - ); - toastr.success( - "¡Comada gratis para " + - SC_Personas[data.Persona].Nombre + - "!" - ); - } else { - SC_Personas[data.Persona].Puntos = parseInt(SC_Personas[data.Persona].Puntos) + 1; - toastr.success("¡Comada DE PAGO!"); - } - TS_encrypt(SC_Personas[data.Persona], SECRET, (encrypted) => { - betterGunPut( - gun.get(TABLE).get("personas").get(data.Persona), - encrypted - ); + data.Estado = state; + TS_encrypt(data, SECRET, (encrypted) => { + betterGunPut(ref.get(data._key), encrypted); + toastr.success("Guardado!"); }); return false; }; - - // Add all buttons to td with line breaks between - buttons.forEach((button) => { - td.appendChild(button); - td.appendChild(document.createElement("br")); - }); - td.appendChild(paidButton); - new_tr.appendChild(td); - - // Event handlers are now attached during button creation - break; - case "persona": - if (key.self == true) { - var persona = data - } else { - var persona = SC_Personas[data[key.key]] || {}; + return button; + }; + const buttons = [ + createButton("Pedido", "Pedido"), + createButton("En preparación", "En preparación"), + createButton("Listo", "Listo"), + createButton("Entregado", "Entregado"), + createButton("Deuda", "Deuda"), + ]; + const paidButton = document.createElement("button"); + paidButton.textContent = "Pagado"; + paidButton.onclick = (event) => { + event.preventDefault(); + event.stopPropagation(); + if (!confirm("¿Quieres marcar como pagado? - Se borrara la comanda y se actualizarán los puntos.")) { + return false; } - - const regco = stringToColour( - (persona.Region || "?").toLowerCase() - ); - - const tdPersona = document.createElement("td"); - tdPersona.style.textAlign = "center"; - tdPersona.style.fontSize = "20px"; - tdPersona.style.backgroundColor = regco; - tdPersona.style.color = colorIsDarkAdvanced(regco); - - const regionSpan = document.createElement("span"); - regionSpan.style.fontSize = "40px"; - regionSpan.style.textTransform = "capitalize"; - regionSpan.textContent = (persona.Region || "?").toLowerCase(); - tdPersona.appendChild(regionSpan); - - tdPersona.appendChild(document.createElement("br")); - - const infoSpan = document.createElement("span"); - infoSpan.style.backgroundColor = "white"; - infoSpan.style.border = "2px solid black"; - infoSpan.style.borderRadius = "5px"; - infoSpan.style.display = "inline-block"; - infoSpan.style.padding = "5px"; - infoSpan.style.color = "black"; - - const img = document.createElement("img"); - img.src = persona.Foto || "static/ico/user_generic.png"; - img.height = 70; - infoSpan.appendChild(img); - - infoSpan.appendChild(document.createElement("br")); - infoSpan.appendChild( - document.createTextNode(persona.Nombre || "") - ); - - infoSpan.appendChild(document.createElement("br")); - const pointsSpan = document.createElement("span"); - pointsSpan.style.fontSize = "17px"; - pointsSpan.textContent = (persona.Puntos || "0") + " puntos."; - infoSpan.appendChild(pointsSpan); - - tdPersona.appendChild(infoSpan); - new_tr.appendChild(tdPersona); - break; - - default: - break; + data.Estado = "Pagado"; + betterGunPut(ref.get(data._key), null); + toastr.success("Guardado!"); + if (SC_Personas[data.Persona].Puntos >= 10 && confirm("¿Pagar con Puntos? - Cancela para pagar con Efectivo.")) { + SC_Personas[data.Persona].Puntos = parseInt(SC_Personas[data.Persona].Puntos) - 10; + toastr.success("¡Comada gratis para " + SC_Personas[data.Persona].Nombre + "!"); + toastr.success("¡Comada gratis para " + SC_Personas[data.Persona].Nombre + "!"); + } else { + SC_Personas[data.Persona].Puntos = parseInt(SC_Personas[data.Persona].Puntos) + 1; + toastr.success("¡Comada DE PAGO!"); + } + TS_encrypt(SC_Personas[data.Persona], SECRET, (encrypted) => { + betterGunPut(gun.get(TABLE).get("personas").get(data.Persona), encrypted); + }); + return false; + }; + buttons.forEach((button) => { + td.appendChild(button); + td.appendChild(document.createElement("br")); + }); + td.appendChild(paidButton); + new_tr.appendChild(td); + break; } - }); - new_tr.onclick = (event) => { - setUrlHash(pageco + "," + data._key); - }; + case "persona": { + let persona = key.self === true ? data : SC_Personas[data[key.key]] || {}; + const regco = stringToColour((persona.Region || "?").toLowerCase()); + const tdPersona = document.createElement("td"); + tdPersona.style.textAlign = "center"; + tdPersona.style.fontSize = "20px"; + tdPersona.style.backgroundColor = regco; + tdPersona.style.color = colorIsDarkAdvanced(regco); + const regionSpan = document.createElement("span"); + regionSpan.style.fontSize = "40px"; + regionSpan.style.textTransform = "capitalize"; + regionSpan.textContent = (persona.Region || "?").toLowerCase(); + tdPersona.appendChild(regionSpan); + tdPersona.appendChild(document.createElement("br")); + const infoSpan = document.createElement("span"); + infoSpan.style.backgroundColor = "white"; + infoSpan.style.border = "2px solid black"; + infoSpan.style.borderRadius = "5px"; + infoSpan.style.display = "inline-block"; + infoSpan.style.padding = "5px"; + infoSpan.style.color = "black"; + const img = document.createElement("img"); + img.src = persona.Foto || "static/ico/user_generic.png"; + img.height = 70; + infoSpan.appendChild(img); + infoSpan.appendChild(document.createElement("br")); + infoSpan.appendChild(document.createTextNode(persona.Nombre || "")); + infoSpan.appendChild(document.createElement("br")); + const pointsSpan = document.createElement("span"); + pointsSpan.style.fontSize = "17px"; + pointsSpan.textContent = (persona.Puntos || "0") + " puntos."; + infoSpan.appendChild(pointsSpan); + tdPersona.appendChild(infoSpan); + new_tr.appendChild(tdPersona); + break; + } + default: + break; + } }); + new_tr.onclick = (event) => { + setUrlHash(pageco + "," + data._key); + }; + fragment.appendChild(new_tr); + } + // Replace tbody in one operation + tablebody_EL.innerHTML = ""; + tablebody_EL.appendChild(fragment); } ref.map().on((data, key, _msg, _ev) => { EventListeners.GunJS.push(_ev); diff --git a/src/page/materiales.js b/src/page/materiales.js index adaf9a9..dd5d292 100644 --- a/src/page/materiales.js +++ b/src/page/materiales.js @@ -175,12 +175,11 @@ PAGES.materiales = { gun.get(TABLE).get("materiales"), document.getElementById("tableContainer"), undefined, - undefined, - //function(data) { - // if (data.Ubicacion == filtroUbicacion) {return false} - // if (filtroUbicacion == "") {return false} - // return true - //} + function(data) { + if (data.Ubicacion == filtroUbicacion) {return false} + if (filtroUbicacion == "") {return false} + return true + } ); }