diff --git a/assets/load.gif b/assets/load.gif new file mode 100644 index 0000000..94bfef5 Binary files /dev/null and b/assets/load.gif differ diff --git a/assets/static/euskaditech-css/simple.css b/assets/static/euskaditech-css/simple.css index 13cb3f2..d22f9f4 100644 --- a/assets/static/euskaditech-css/simple.css +++ b/assets/static/euskaditech-css/simple.css @@ -1,306 +1,307 @@ - - html { - color-scheme: light only; - } - - body { - font-family: Arial, Helvetica, sans-serif; - } - - main { - /*max-width: 45rem; - margin: 0 auto;*/ - padding: 0 15px; - } - - .supermesh-indicator { - border-top-left-radius: 15px; - background-color: greenyellow; - border-top: 5px solid green; - border-left: 5px solid green; - padding: 15px; - max-width: 30rem; - position: fixed; - right: 0; - bottom: 0; - color: black; - display: none; - } - - .supermesh-indicator a { - color: blue; - } - - details.supermesh-indicator summary { - font-size: unset; - } - - .link, - a { - color: blue; - text-decoration: underline; - cursor: pointer; - } - - .link:hover, - a:hover { - text-decoration: underline; - } - - #articleID { - font-family: monospace; - } - - @media (prefers-color-scheme: dark) { - .link, - a { - color: lightblue; - } - } - - @media print { - .supermesh-indicator, - .no_print { - display: none; - } - } - - main { - margin-bottom: 25rem; - } - - button, - .button { - display: inline-block; - padding: 5px 10px; - background-color: beige; - border: 2px solid black; - font-size: 20px; - margin: 3px; - text-decoration: none; - color: black; - } - - button:hover, - .button:hover { - text-decoration: underline; - } - - /* https://coolors.co/palette/ff0000-ff8700-ffd300-deff0a-a1ff0a-0aff99-0aefff-147df5-580aff-be0aff */ - .rojo { - background: #ff0000; - color: white; - } - - .btn1 { - background: #ff0000; - color: white; - } - - .btn2 { - background: #ff8700; - color: white; - } - - .btn3 { - background: #ffd300; - color: black; - } - - .btn4 { - background: #deff0a; - color: black; - } - - .btn5 { - background: #a1ff0a; - color: black; - } - - .btn6 { - background: #0aff99; - color: black; - } - - .btn7 { - background: #0aefff; - color: black; - } - - .btn8 { - background: #147df5; - color: white; - } - - .nav-disabled { - background: black !important; - color: grey !important; - } - - .nav-disabled:hover { - text-decoration: unset !important; - } - - input, - select, - textarea { - font-size: 18px; - padding: 5px; - width: calc(100% - 11px); - } - - select { - width: 100%; - } - - details input, - details select, - details textarea { - font-size: 18px; - padding: 5px; - width: calc(100% - 15px); - } - - input[type="color"] { - width: 50px; - height: 50px; - } - - textarea { - height: 150px; - } - - details summary { - font-size: 20px; - } - - thead tr { - background-color: black; - color: white; - } - - table { - display: block; - line-break: loose; - width: fit-content; - min-width: 750px; - border: 1px solid black; - } - - table tr th { - line-break: auto; - } - - table tr td { - border-bottom: 3px solid black !important; - padding: 5px; - } - - .scase { - text-transform: lowercase; - } - - .scase:first-letter { - text-transform: uppercase; - } - - table tr:hover td { - text-decoration: underline; - background: rgba(200, 200, 200, 0.5); - /* color: black; */ - } - - table tr:hover td.TextBorder { - background: inherit; - color: inherit; - text-decoration: none; - } - - fieldset { - max-width: 25rem; - } - - .TextBorder { - color: black; - text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, - 1px 1px 0 #fff; - -webkit-text-stroke: 0.25px #fff; - } - - code { - font-size: x-small; - color: gray; - } - - .activeSCButton { - border: 7px dashed beige; - color: beige; - background: black !important; - } - - .btn1.activeSCButton { - border-color: #ff0000; - color: #ff0000; - } - - .btn2.activeSCButton { - border-color: #ff8700; - color: #ff8700; - } - - .btn3.activeSCButton { - border-color: #ffd300; - color: #ffd300; - } - - .btn4.activeSCButton { - border-color: #deff0a; - color: #deff0a; - } - - .btn5.activeSCButton { - border-color: #a1ff0a; - color: #a1ff0a; - } - - .btn6.activeSCButton { - border-color: #0aff99; - color: #0aff99; - } - - .btn7.activeSCButton { - border-color: #0aefff; - color: #0aefff; - } - - .btn8.activeSCButton { - border-color: #147df5; - color: #147df5; - } - - hr { - border-color: black; - border-style: solid; - } - - #snackbar { - visibility: hidden; - /* min-width: 250px; */ - background-color: #333; - color: #fff; - text-align: center; - border-radius: 2px; - padding: 16px; - position: fixed; - z-index: 1; - right: 70px; - bottom: 25px; - } - - #snackbar a { - color: lightblue; - } - - #snackbar.show { - visibility: visible; +html { + color-scheme: light only; } + +body { + font-family: Arial, Helvetica, sans-serif; +} + +main { + /*max-width: 45rem; + margin: 0 auto;*/ + padding: 0 15px; +} + +.supermesh-indicator { + border-top-left-radius: 15px; + background-color: greenyellow; + border-top: 5px solid green; + border-left: 5px solid green; + padding: 15px; + max-width: 30rem; + position: fixed; + right: 0; + bottom: 0; + color: black; + display: none; +} + +.supermesh-indicator a { + color: blue; +} + +details.supermesh-indicator summary { + font-size: unset; +} + +.link, +a { + color: blue; + text-decoration: underline; + cursor: pointer; +} + +.link:hover, +a:hover { + text-decoration: underline; +} + +#articleID { + font-family: monospace; +} + +@media (prefers-color-scheme: dark) { + + .link, + a { + color: lightblue; + } +} + +@media print { + + .supermesh-indicator, + .no_print { + display: none; + } +} + +main { + margin-bottom: 25rem; +} + +button, +.button { + display: inline-block; + padding: 5px 10px; + background-color: beige; + border: 2px solid black; + font-size: 20px; + margin: 3px; + text-decoration: none; + color: black; +} + +button:hover, +.button:hover { + text-decoration: underline; +} + +/* https://coolors.co/palette/ff0000-ff8700-ffd300-deff0a-a1ff0a-0aff99-0aefff-147df5-580aff-be0aff */ +.rojo { + background: #ff0000; + color: white; +} + +.btn1 { + background: #ff0000; + color: white; +} + +.btn2 { + background: #ff8700; + color: white; +} + +.btn3 { + background: #ffd300; + color: black; +} + +.btn4 { + background: #deff0a; + color: black; +} + +.btn5 { + background: #a1ff0a; + color: black; +} + +.btn6 { + background: #0aff99; + color: black; +} + +.btn7 { + background: #0aefff; + color: black; +} + +.btn8 { + background: #147df5; + color: white; +} + +.nav-disabled { + background: black !important; + color: grey !important; +} + +.nav-disabled:hover { + text-decoration: unset !important; +} + +input, +select, +textarea { + font-size: 18px; + padding: 5px; + width: calc(100% - 11px); +} + +select { + width: 100%; +} + +details input, +details select, +details textarea { + font-size: 18px; + padding: 5px; + width: calc(100% - 15px); +} + +input[type="color"] { + width: 50px; + height: 50px; +} + +textarea { + height: 150px; +} + +details summary { + font-size: 20px; +} + +thead tr { + background-color: black; + color: white; +} + +table { + display: block; + line-break: loose; + width: fit-content; + min-width: 750px; + border: 1px solid black; +} + +table tr th { + line-break: auto; +} + +table tr td { + border-bottom: 3px solid black !important; + padding: 5px; +} + +.scase { + text-transform: lowercase; +} + +.scase:first-letter { + text-transform: uppercase; +} + +table tr:hover td { + text-decoration: underline; + background: rgba(200, 200, 200, 0.5); + /* color: black; */ +} + +table tr:hover td.TextBorder { + background: inherit; + color: inherit; + text-decoration: none; +} + +fieldset { + max-width: 25rem; +} + +.TextBorder { + color: black; + text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, + 1px 1px 0 #fff; + -webkit-text-stroke: 0.25px #fff; +} + +code { + font-size: x-small; + color: gray; +} + +.activeSCButton { + border: 7px dashed beige; + color: beige; + background: black !important; +} + +.btn1.activeSCButton { + border-color: #ff0000; + color: #ff0000; +} + +.btn2.activeSCButton { + border-color: #ff8700; + color: #ff8700; +} + +.btn3.activeSCButton { + border-color: #ffd300; + color: #ffd300; +} + +.btn4.activeSCButton { + border-color: #deff0a; + color: #deff0a; +} + +.btn5.activeSCButton { + border-color: #a1ff0a; + color: #a1ff0a; +} + +.btn6.activeSCButton { + border-color: #0aff99; + color: #0aff99; +} + +.btn7.activeSCButton { + border-color: #0aefff; + color: #0aefff; +} + +.btn8.activeSCButton { + border-color: #147df5; + color: #147df5; +} + +hr { + border-color: black; + border-style: solid; +} + +#snackbar { + visibility: hidden; + /* min-width: 250px; */ + background-color: #333; + color: #fff; + text-align: center; + border-radius: 2px; + padding: 16px; + position: fixed; + z-index: 1; + right: 70px; + bottom: 25px; +} + +#snackbar a { + color: lightblue; +} + +#snackbar.show { + visibility: visible; +} \ No newline at end of file diff --git a/src/app_modules.js b/src/app_modules.js index 3982d67..39b18dc 100644 --- a/src/app_modules.js +++ b/src/app_modules.js @@ -628,7 +628,7 @@ function TS_IndexElement( container, rowCallback = undefined, canAddCallback = undefined, - globalSearchBar = true, + globalSearchBar = true ) { // Every item in config should have: // key: string @@ -639,14 +639,18 @@ function TS_IndexElement( var tablehead = safeuuid(); var scrolltable = safeuuid(); var searchKeyInput = safeuuid(); - + // Create the container with search bar and table container.innerHTML = `
- - + + + + @@ -662,14 +666,17 @@ function TS_IndexElement( }); // Add search functionality const searchKeyEl = document.getElementById(searchKeyInput); - searchKeyEl.addEventListener('input', debounce(() => render(), 300)); + searchKeyEl.addEventListener( + "input", + debounce(() => render(), 300) + ); function searchInData(data, searchValue, config) { if (!searchValue) return true; - + // Search in ID if (data._key.toLowerCase().includes(searchValue)) return true; - + // Search in configured fields for (const field of config) { const value = data[field.key]; @@ -681,9 +688,12 @@ function TS_IndexElement( try { const comandaData = JSON.parse(data.Comanda); // Search in all comanda fields - if (Object.values(comandaData).some(v => - String(v).toLowerCase().includes(searchValue) - )) return true; + if ( + Object.values(comandaData).some((v) => + String(v).toLowerCase().includes(searchValue) + ) + ) + return true; } catch (e) { // If JSON parse fails, search in raw string if (data.Comanda.toLowerCase().includes(searchValue)) return true; @@ -693,8 +703,10 @@ function TS_IndexElement( const persona = SC_Personas[value]; if (persona) { // Search in persona fields - if (persona.Nombre?.toLowerCase().includes(searchValue)) return true; - if (persona.Region?.toLowerCase().includes(searchValue)) return true; + if (persona.Nombre?.toLowerCase().includes(searchValue)) + return true; + if (persona.Region?.toLowerCase().includes(searchValue)) + return true; } break; default: @@ -715,7 +727,7 @@ function TS_IndexElement( } return 0; } - + const searchValue = searchKeyEl.value.toLowerCase().trim(); tablebody_EL.innerHTML = ""; Object.entries(rows) @@ -747,6 +759,7 @@ function TS_IndexElement( break; case "comanda": const tdComanda = document.createElement("td"); + tdComanda.style.verticalAlign = "top"; const parsedComanda = JSON.parse(data.Comanda); const precio = SC_priceCalc(parsedComanda)[0]; @@ -758,18 +771,26 @@ function TS_IndexElement( 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.appendChild(spanPrecio); + pre.innerHTML = "Ticket de compra "; pre.appendChild(document.createTextNode("\n")); pre.innerHTML += - SC_parse_short(parsedComanda) + "
" + data.Notas; + SC_parse_short(parsedComanda) + "
" + data.Notas + "
"; + pre.appendChild(spanPrecio); tdComanda.appendChild(pre); new_tr.appendChild(tdComanda); @@ -945,7 +966,7 @@ function TS_IndexElement( } const PAGES = {}; -document.addEventListener("DOMContentLoaded", () => { +function SetPages() { Object.keys(PAGES).forEach((key) => { if (PAGES[key].Esconder == true) { return; @@ -956,5 +977,24 @@ document.addEventListener("DOMContentLoaded", () => { a.innerText = PAGES[key].Title; document.getElementById("appendApps").append(a); }); - open_page(location.hash.replace("#", "")); +} +document.addEventListener("DOMContentLoaded", () => { + SetPages(); + document.getElementById("appendApps").style.display = "none"; + document.getElementById("loading").style.display = "block"; }); +var Booted = false; +getPeers(); +setInterval(() => { + getPeers(); + if (ConnectionStarted && !Booted) { + Booted = true; + document.getElementById("loading").style.display = "none"; + if (!SUB_LOGGED_IN) { + open_page("login"); + return; + } + document.getElementById("appendApps").style.display = "block"; + open_page(location.hash.replace("#", "")); + } +}, 1500); diff --git a/src/config.js b/src/config.js index 4d4eccc..abc9d4f 100644 --- a/src/config.js +++ b/src/config.js @@ -22,4 +22,23 @@ const RELAYS = [ var SECRET = ""; var SUB_LOGGED_IN = false; var SUB_LOGGED_IN_DETAILS = false; -var SUB_LOGGED_IN_ID = false; \ No newline at end of file +var SUB_LOGGED_IN_ID = false; +if (urlParams.get("sublogin") != null) { + SUB_LOGGED_IN = true; + SUB_LOGGED_IN_ID = urlParams.get("sublogin"); + SUB_LOGGED_IN_DETAILS = true; + setTimeout(() => { + SUB_LOGGED_IN_DETAILS = SC_Personas[SUB_LOGGED_IN_ID]; + }, 1500); +} +function LogOutTeleSec() { + SUB_LOGGED_IN = false; + SUB_LOGGED_IN_DETAILS = false; + SUB_LOGGED_IN_ID = false; + document.getElementById("appendApps").style.display = "none"; + document.getElementById("loading").style.display = "block"; + //Remove sublogin from URL and reload + urlParams.delete("sublogin"); + history.replaceState(null, "", "?" + urlParams.toString()); + location.reload(); +} \ No newline at end of file diff --git a/src/gun_init.js b/src/gun_init.js index cb2b3bc..f5b1205 100644 --- a/src/gun_init.js +++ b/src/gun_init.js @@ -14,48 +14,76 @@ function removeCache() { location.reload(true); }); } -function getPeers() { - var peerCount = 0; - var peerCountEl = document.getElementById("peerCount"); - var peerListEl = document.getElementById("peerList"); - var list = document.createElement("ul"); - document.getElementById("peerPID").innerText = "PID " + gun.back("opt.pid"); - Object.values(gun.back("opt.peers")).forEach((peer) => { - if ( - peer.wire != undefined && - (peer.wire.readyState == 1 || peer.wire.readyState == "open") - ) { - peerCount += 1; - var wireType = peer.wire.constructor.name; - var wireHType = peer.wire.constructor.name; - var wireID = peer.id; - switch (wireType) { - case "WebSocket": - wireHType = "Web"; - wireID = wireID.split("/")[2]; - break; - case "RTCDataChannel": - wireHType = "Mesh"; - wireID = peer.id; - } - var el = document.createElement("li"); - el.innerText = `Nodo ${wireHType}: ${wireID}`; - list.append(el); - } - }); - peerListEl.innerHTML = list.innerHTML; - peerCountEl.innerText = peerCount; +var AtLeastThreePeers = false; +var ConnectionStarted = false; +function formatPeerInfo(peer) { + const wireType = peer.wire.constructor.name; + let wireHType = wireType; + let wireID = peer.id; + + switch (wireType) { + case "WebSocket": + wireHType = "Web"; + wireID = wireID.split("/")[2]; + break; + case "RTCDataChannel": + wireHType = "Mesh"; + break; + } + + return { wireHType, wireID }; +} + +function isPeerConnected(peer) { + return peer.wire != undefined && + (peer.wire.readyState == 1 || peer.wire.readyState == "open"); +} + +function createPeerListElement(wireHType, wireID) { + const el = document.createElement("li"); + el.innerText = `Nodo ${wireHType}: ${wireID}`; + return el; +} + +function updateConnectionStatus(peerCount) { + const statusImage = peerCount < 3 ? "connect_ko.svg" : "connect_ok.svg"; + document.getElementById("connectStatus").src = `static/ico/${statusImage}`; + if (peerCount < 3) { - document.getElementById("connectStatus").src = "static/ico/connect_ko.svg"; - gun.opt({ peers: RELAYS }); + if (!window.peerRetryCount) window.peerRetryCount = 0; + window.peerRetryCount = (window.peerRetryCount + 1) % 3; + if (window.peerRetryCount === 0) { + gun.opt({ peers: RELAYS }); + } + AtLeastThreePeers = false; } else { - document.getElementById("connectStatus").src = "static/ico/connect_ok.svg"; + ConnectionStarted = true; + AtLeastThreePeers = true; } } -getPeers(); -setInterval(() => { - getPeers(); -}, 2500); + +function getPeers() { + const peerCountEl = document.getElementById("peerCount"); + const peerListEl = document.getElementById("peerList"); + const list = document.createElement("ul"); + + document.getElementById("peerPID").innerText = "PID " + gun.back("opt.pid"); + + const connectedPeers = Object.values(gun.back("opt.peers")) + .filter(isPeerConnected) + .map(peer => { + const { wireHType, wireID } = formatPeerInfo(peer); + return createPeerListElement(wireHType, wireID); + }); + + connectedPeers.forEach(el => list.append(el)); + + peerListEl.innerHTML = list.innerHTML; + const peerCount = connectedPeers.length; + peerCountEl.innerText = peerCount; + + updateConnectionStatus(peerCount); +} function safeuuid(prefix = "AXLUID_") { return prefix + crypto.randomUUID().split("-")[4]; } diff --git a/src/index.html b/src/index.html index 7e77ed2..f336ae6 100644 --- a/src/index.html +++ b/src/index.html @@ -12,6 +12,7 @@ +
SuperMesh
diff --git a/src/page/index.js b/src/page/index.js index 145327d..b4cda89 100644 --- a/src/page/index.js +++ b/src/page/index.js @@ -3,9 +3,10 @@ PAGES.index = { Title: "Inicio", index: function () { container.innerHTML = ` -

Inicio

+

¡Hola, ${SUB_LOGGED_IN_DETAILS.Nombre}!

Utiliza el menú superior para abrir un modulo

+ `; }, }; diff --git a/src/page/login.js b/src/page/login.js index dc97e42..f3a568e 100644 --- a/src/page/login.js +++ b/src/page/login.js @@ -15,7 +15,7 @@ PAGES.login = { - Acceso sin cuenta + Acceso sin cuenta - No disponible `; var divact = document.getElementById(div_actions); addCategory_Personas(
+ +