Upozornění:
Veškerý zde vystavený kód je mým autorským dílem a je zveřejněn výhradně za účelem ukázky stylu mé práce.
Kód slouží pouze k nahlédnutí – jakékoliv kopírování, šíření, úpravy či jiné využití bez mého výslovného souhlasu nejsou povoleny.
Zůstává mým duševním vlastnictvím ve smyslu autorského zákona.
Děkuji za pochopení.
← Zpět na seznam

RoSaaRi (JS)



  let currentCallback = null;
  
  function aktualizujStavPalivaVHlavicce() {
    const el = document.getElementById("stav_v_nadrzi_l");
    const palivo = parseFloat(localStorage.getItem("stav_v_nadrzi_l"));
    if (el && !isNaN(palivo)) {
      el.textContent = palivo;
      el.classList.toggle("palivo-nizke", palivo < 10);
    }
  }
  
  window.addEventListener("DOMContentLoaded", () => {
  
    function prepocitejStavPaliva() {
      const spotreba = parseFloat(localStorage.getItem("spotreba")) || 0;
      const lastTach = parseInt(localStorage.getItem("lastTach")) || 0;
      const predchoziTach = parseInt(localStorage.getItem("predchoziTach")) || parseInt(localStorage.getItem("startKm")) || 0;
      let puvodniStav = parseFloat(localStorage.getItem("stav_v_nadrzi_l")) || 0;
    
      if (!spotreba || !lastTach || lastTach < predchoziTach) return;
    
      const rozdilKm = lastTach - predchoziTach;
      const spaleno = (rozdilKm * spotreba) / 100;
      const zustatek = puvodniStav - spaleno;
    
      const zaokrouhleno = Math.round(zustatek * 2) / 2;
      localStorage.setItem("stav_v_nadrzi_l", zaokrouhleno);
      localStorage.setItem("predchoziTach", lastTach);
      aktualizujStavPalivaVHlavicce();
    }
    const smena = localStorage.getItem("smena") || "P";
    const datum = localStorage.getItem("datum") || new Date().toLocaleDateString("cs-CZ");
    const jmeno = localStorage.getItem("ridic") || "Neznámý řidič";
  
    const modal = document.getElementById("modal");
    const modalInput = document.getElementById("modal-input");
    const modalInputMode = document.getElementById("modal-input-mode");
    const btnNumericMode = document.getElementById("btn-numeric-mode");
    const btnMicMode = document.getElementById("btn-mic-mode");
    const modalTitle = document.getElementById("modal-title");
    const modalOk = document.getElementById("modal-ok");
    const modalCancel = document.getElementById("modal-cancel");
    const flagSedacka = document.getElementById("flag-sedacka");
    const flagVleze = document.getElementById("flag-vleze");
    
    const transportFlags = document.querySelectorAll(".transport-flag");
  
    transportFlags.forEach(flag => {
      flag.addEventListener("change", () => {
      
        if (flag.checked) {
          transportFlags.forEach(other => {
            if (other !== flag) {
              other.checked = false;
            }
          });
        }
      
        const nekteryZaskrtnuty =
          [...transportFlags].some(f => f.checked);
      
        modalInput.disabled = !nekteryZaskrtnuty;
      
        if (!nekteryZaskrtnuty) {
          modalInput.value = "";
        }
      });
    });
  
    function nastavFlagyModalu(zobrazit) {
      const box = document.getElementById("modal-flags");
      const doprovod = document.getElementById("flag-doprovod");
    
      if (!box) return;
    
      box.style.display = zobrazit ? "block" : "none";
    
      if (doprovod) doprovod.checked = false;
    
      document.querySelectorAll(".transport-flag").forEach(f => {
        f.checked = false;
      });
    
      modalInput.disabled = zobrazit;
    }
  
    function nastavCiselnyVstup(rezim) {
      if (!modalInputMode || !btnNumericMode || !btnMicMode) return;
    
      modalInput.removeAttribute("inputmode");
      modalInput.removeAttribute("pattern");
      modalInput.removeAttribute("autocomplete");
    
      if (rezim === "rc") {
        modalInputMode.classList.remove("hidden");
      
        btnMicMode.classList.add("active");
        btnNumericMode.classList.remove("active");
        return;
      }
    
      if (rezim === "numeric") {
        modalInputMode.classList.add("hidden");
      
        modalInput.setAttribute("inputmode", "numeric");
        modalInput.setAttribute("pattern", "[0-9]*");
        modalInput.setAttribute("autocomplete", "off");
        return;
      }
    
      modalInputMode.classList.add("hidden");
      btnMicMode.classList.remove("active");
      btnNumericMode.classList.remove("active");
    }
  
    if (btnNumericMode && btnMicMode) {
      btnMicMode.onclick = () => {
        modalInput.blur();
      
        setTimeout(() => {
          modalInput.removeAttribute("inputmode");
          modalInput.removeAttribute("pattern");
          modalInput.removeAttribute("autocomplete");
        
          btnMicMode.classList.add("active");
          btnNumericMode.classList.remove("active");
        
          modalInput.focus();
        }, 100);
      };
    
      btnNumericMode.onclick = () => {
        modalInput.blur();
      
        setTimeout(() => {
          modalInput.setAttribute("inputmode", "numeric");
          modalInput.setAttribute("pattern", "[0-9]*");
          modalInput.setAttribute("autocomplete", "off");
        
          btnNumericMode.classList.add("active");
          btnMicMode.classList.remove("active");
        
          modalInput.focus();
        }, 100);
      };
    }
  
    function showModal(title, placeholder = "", callback, zobrazitFlagy = false, rezimVstupu = "text") {
      modalTitle.textContent = title;
      modalInput.value = placeholder;
    
      nastavCiselnyVstup(rezimVstupu);
    
      nastavFlagyModalu(zobrazitFlagy);
    
      modal.classList.remove("hidden");
      modalInput.focus();
      currentCallback = callback;
    }
  
    function closeModal() {
      modal.classList.add("hidden");
      modalInput.value = "";
      currentCallback = null;
    }
  
    function ziskejFlagyPoznamky() {
      const flagy = [];
    
      if (document.getElementById("flag-dojde")?.checked) {
        flagy.push("DOJDE");
      }
    
      if (document.getElementById("flag-spomoci")?.checked) {
        flagy.push("S POMOCÍ");
      }
    
      if (document.getElementById("flag-sedacka")?.checked) {
        flagy.push("SEDAČKA");
      }
    
      if (document.getElementById("flag-vleze")?.checked) {
        flagy.push("V LEŽE");
      }
    
      if (document.getElementById("flag-doprovod")?.checked) {
        flagy.push("DOPROVOD");
      }
    
      return flagy.join(" | ");
    }
  
    modalOk.onclick = () => {
      const value = modalInput.value.trim();
      const cb = currentCallback;
      closeModal();
      if (cb) setTimeout(() => cb(value), 0);
    };
  
    modalCancel.onclick = closeModal;
  
    function zpracujKodovouPoznamku(poznamka) {
      const cista = String(poznamka || "").replace(/\D/g, "");
    
      if (cista.length < 12 || cista.length > 13) {
        alert(
          `Rodné číslo nebylo rozpoznáno.\n\n` +
          `Zadáno: ${poznamka}\n` +
          `Rozpoznané číslice: ${cista}\n` +
          `Počet číslic: ${cista.length}\n\n` +
          `Zadejte rodné číslo znovu.`
        );
        return null;
      }
    
      const rc = cista.slice(0, -3);
      const pojistovna = cista.slice(-3);
    
      if (rc.length !== 9 && rc.length !== 10) {
        alert(
          `Rodné číslo má špatnou délku.\n\n` +
          `RČ: ${rc}\n` +
          `Pojišťovna: ${pojistovna}`
        );
        return null;
      }
    
      return {
        personal_id: rc,
        pojistovna
      };
    }
  
  
    function zobrazZaznamy() {
      const vypisy = document.getElementById("vypisy");
      if (!vypisy || typeof getVsechnyZaznamy !== 'function') return;
    
      vypisy.innerHTML = "";
      getVsechnyZaznamy().then(data => {
        const nevylozene = data.filter(z => !z.cas_vylozeni).sort((a, b) => a.id - b.id);
        nevylozene.slice(-5).forEach(z => {
          const div = document.createElement("div");
          div.className = "zaznam";
          div.dataset.id = z.id;
          div.textContent =  `${z.cas_nalozeni || "-"} | ${z.mesto_nalozeni} | ${z.poznamka}`;
          if (z.typ === "kodovy") {
            div.textContent += z.personal_id
              ? ` | RČ: ${z.personal_id} / ${z.pojistovna}`
              : ` | ⚠️ RČ CHYBÍ`;
          }
          div.onclick = () => div.classList.toggle("selected");
          vypisy.appendChild(div);
        });
      });
    }
  
    function ziskejOznaceneZaznamy(callback) {
      return getVsechnyZaznamy().then(vsechny => {
        const oznaceneDivy = document.querySelectorAll(".zaznam.selected");
        const ids = [...oznaceneDivy].map(div => parseInt(div.dataset.id));
        return vsechny.filter(z => ids.includes(z.id));
      });
    }
  
    function aktualizujTachometrVHlavicce() {
      const tach = localStorage.getItem("lastTach");
      const el = document.getElementById("tach-info");
      if (el) {
        el.textContent = tach ? `Tachometr: ${tach} km` : `Tachometr: —`;
      }
    }
  
    function prevedCas(vstup) {
      const cista = String(vstup || "").replace(/\D/g, "");
    
      if (!cista) return null;
    
      let hodiny;
      let minuty;
    
      if (cista.length <= 2) {
        hodiny = parseInt(cista, 10);
        minuty = 0;
      } else if (cista.length === 3) {
        hodiny = parseInt(cista.slice(0, 1), 10);
        minuty = parseInt(cista.slice(1), 10);
      } else if (cista.length === 4) {
        hodiny = parseInt(cista.slice(0, 2), 10);
        minuty = parseInt(cista.slice(2), 10);
      } else {
        return null;
      }
    
      if (
        isNaN(hodiny) ||
        isNaN(minuty) ||
        hodiny < 0 ||
        hodiny > 23 ||
        minuty < 0 ||
        minuty > 59
      ) {
        return null;
      }
    
      return String(hodiny).padStart(2, "0") + ":" + String(minuty).padStart(2, "0");
    }
  
    function ziskejCas(callback) {
      const now = new Date();
      const hhmm = now.toTimeString().slice(0, 5);
    
      showModal("Zadejte čas", hhmm, vstup => {
        const cas = prevedCas(vstup);
      
        if (!cas) {
          alert(
            "Neplatný čas.\n\n" +
            "Příklady:\n" +
            "709 = 07:09\n" +
            "945 = 09:45\n" +
            "1322 = 13:22\n" +
            "7 = 07:00"
          );
        
          ziskejCas(callback);
          return;
        }
      
        callback(cas);
      }, false, "numeric");
    }
  
    function ziskejMesto(callback) {
      if (!navigator.onLine || !navigator.geolocation) {
        showModal("Zadejte město", "", callback);
        return;
      }
    
      navigator.geolocation.getCurrentPosition(
        pos => {
          const { latitude, longitude } = pos.coords;
        
          if (!navigator.onLine) {
            showModal("Zadejte město", "", callback);
            return;
          }
        
          fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${latitude}&lon=${longitude}&accept-language=cs`)
            .then(res => res.json())
            .then(data => {
              const adresa = data.address || {};
              const mesto =
                adresa.city ||
                adresa.town ||
                adresa.village ||
                adresa.municipality ||
                "";
            
              showModal("Potvrďte nebo upravte město", mesto, callback);
            })
            .catch(() => {
              showModal("Zadejte město", "", callback);
            });
        },
        () => {
          showModal("Zadejte město", "", callback);
        },
        {
          enableHighAccuracy: false,
          timeout: 2500,
          maximumAge: 300000
        }
      );
    }
  
    function ziskejPoznamku(callback) {
      showModal("Zadejte poznámku", "", callback);
    }
  
    function vytvorZaznam(zaznam) {
      if (typeof addZaznam === "function") {
        return addZaznam(zaznam);
      }
    
      alert("Lokální databáze není připravená. Zkus znovu načíst aplikaci.");
      return Promise.reject(new Error("addZaznam není dostupná"));
    }
  
    function procesPrazdny() {
      ziskejPoznamku(poznamka => {
      
        ziskejMesto(mesto => {
        
          ziskejCas(cas => {
          
            vytvorZaznam({
              id: Date.now(),
              typ: "prazdny",
              kod: null,
              cas_nalozeni: cas,
              mesto_nalozeni: mesto,
              poznamka,
              cas_vylozeni: null,
              mesto_vylozeni: null,
              tachometr: null,
              smena,
              datum,
              ridic: jmeno,
              vozidlo: localStorage.getItem("vozidlo")
            })
          
            .then(() => {
              zobrazZaznamy();
            })
          
            .catch(err => {
              console.error("CHYBA PRI UKLADANI:", err);
            
              alert(
                "Jízdu se nepodařilo uložit.\n\n" +
                (err?.message || err)
              );
            });
          
          });
        
        });
      
      });
    }
  
    function procesKodovy(kod) {
      getVsechnyZaznamy().then(vsechny => {
        const beziPrazdny = vsechny.some(z =>
          z.typ === "prazdny" && !z.cas_vylozeni
        );
      
        if (beziPrazdny) {
          alert("Nejdřív vylož prázdnou jízdu. Kódový převoz nejde spustit, dokud běží prázdný.");
          return;
        }
      
        spustKodovyPrevoz(kod);
      });
    }
    
    function spustKodovyPrevoz(kod) {
      const zaznamy = [];
    
      function zadatRodneCislo(index) {
        showModal(`Zadejte rodné číslo ${index + 1} z ${kod}`, "", val => {
        
          const baseTime = Date.now();
        
          // CHYBĚJÍCÍ RČ
          if (!val.trim() || val.trim() === "?") {
          
            const zaznam = {
              id: baseTime + index,
              typ: "kodovy",
              kod,
              cas_nalozeni: null,
              mesto_nalozeni: null,
              poznamka: ["⚠️ RČ doplnit později", ziskejFlagyPoznamky()]
                .filter(Boolean)
                .join(" | "),
              cas_vylozeni: null,
              mesto_vylozeni: null,
              tachometr: null,
              smena,
              datum,
              ridic: jmeno,
              vozidlo: localStorage.getItem("vozidlo"),
              personal_id: null,
              pojistovna: null,
              rc_doplneno: false
            };
          
            zaznamy.push(zaznam);
          
            if (index + 1 < kod) {
              zadatRodneCislo(index + 1);
            } else {
              ziskejMesto(mesto => {
                ziskejCas(cas => {
                  zaznamy.forEach(z => {
                    z.cas_nalozeni = cas;
                    z.mesto_nalozeni = mesto;
                  });
                
                  Promise.all(
                    zaznamy.map(z => vytvorZaznam(z))
                  ).then(zobrazZaznamy);
                });
              });
            }
          
            return;
          }
        
          // NORMÁLNÍ RČ
          const vysledek = zpracujKodovouPoznamku(val);
        
          if (!vysledek) {
            zadatRodneCislo(index);
            return;
          }
        
          const zaznam = {
            id: baseTime + index,
            typ: "kodovy",
            kod,
            cas_nalozeni: null,
            mesto_nalozeni: null,
            poznamka: ziskejFlagyPoznamky(),
            cas_vylozeni: null,
            mesto_vylozeni: null,
            tachometr: null,
            smena,
            datum,
            ridic: jmeno,
            vozidlo: localStorage.getItem("vozidlo"),
            personal_id: vysledek.personal_id,
            pojistovna: vysledek.pojistovna
          };
        
          zaznamy.push(zaznam);
        
          if (index + 1 < kod) {
            zadatRodneCislo(index + 1);
          } else {
            ziskejMesto(mesto => {
              ziskejCas(cas => {
                zaznamy.forEach(z => {
                  z.cas_nalozeni = cas;
                  z.mesto_nalozeni = mesto;
                });
              
                Promise.all(
                  zaznamy.map(z => vytvorZaznam(z))
                ).then(zobrazZaznamy);
              });
            });
          }
        
        }, true, "rc");
      }
    
      zadatRodneCislo(0);
    }
  
  
  
    function procesVylozeni() {
      const vybrane = document.querySelectorAll(".zaznam.selected");
      if (!vybrane.length) {
        alert("Nejprve vyber záznam.");
        return;
      }
    
      const ids = [...vybrane].map(div => parseInt(div.dataset.id));
    
      getVsechnyZaznamy().then(vsechny => {
        const nevylozene = vsechny.filter(z => !z.cas_vylozeni);
        const zbydePoVylozeni = nevylozene.filter(z => !ids.includes(z.id));
        const jePosledni = zbydePoVylozeni.length === 0;
      
        ziskejMesto(mesto => {
          ziskejCas(cas => {
            const updateZaznam = (id, tach = null, ujetoKm = null) => {
              const update = {
                cas_vylozeni: cas,
                mesto_vylozeni: mesto
              };
              if (tach !== null) update.tachometr = tach;
              if (ujetoKm !== null) update.ujeto_km = ujetoKm;
              return window.updateZaznam(id, update);
            };
          
            const vyloz = (tach, ujetoKm = null) => {
              Promise.all(ids.map(id =>
                updateZaznam(
                  id,
                  tach && id === ids[ids.length - 1] ? tach : null,
                  ujetoKm && id === ids[ids.length - 1] ? ujetoKm : null
                )
              )).then(zobrazZaznamy);
            };
          
            if (jePosledni) {
              const posledniTach = localStorage.getItem("lastTach") || "";
              if (jePosledni) {
              
                function zadatTachometr() {
                
                  const posledniTach = localStorage.getItem("lastTach") || "";
                
                  showModal("Zadejte stav tachometru", posledniTach, tach => {
                  
                    const tachTrim = tach.trim();
                    const pouzeCisla = tachTrim.replace(/\D/g, "");
                  
                    if (pouzeCisla.length !== 6) {
                      alert(
                        "Tachometr musí obsahovat přesně 6 číslic.\n\n" +
                        `Zadáno: ${tachTrim}`
                      );
                    
                      zadatTachometr();
                      return;
                    }
                  
                    let ujetoKm = null;
                  
                    const predchoziTach =
                      parseInt(localStorage.getItem("lastTach")) || 0;
                  
                    const novyTach = parseInt(pouzeCisla);
                  
                    if (
                      !isNaN(novyTach) &&
                      predchoziTach &&
                      novyTach >= predchoziTach
                    ) {
                      ujetoKm = novyTach - predchoziTach;
                    }
                  
                    localStorage.setItem("lastTach", pouzeCisla);
                  
                    aktualizujTachometrVHlavicce();
                    prepocitejStavPaliva();
                  
                    vyloz(pouzeCisla, ujetoKm);
                  }, false, "numeric");
                }
              
                zadatTachometr();
              
              } else {
                vyloz(null);
              }
            } else {
              vyloz(null);
            }
          });
        });
      });
    }
  
    function procesTankovani() {
      const modal = document.getElementById("tankovani-modal");
      const tachInput = document.getElementById("tank-tachometr");
    
      tachInput.value = localStorage.getItem("lastTach") || "";
    
      modal.classList.remove("hidden");
    }
  
    document.getElementById("btn-prazdny").onclick = procesPrazdny;
  
    document.querySelectorAll(".kod-button").forEach(btn => {
      btn.onclick = () => {
        const kod = parseInt(btn.dataset.count);
        procesKodovy(kod);
      };
    });
  
    document.getElementById("btn-vylozit").onclick = procesVylozeni;
    document.getElementById("btn-tankovani").onclick = procesTankovani;
  
    function zavriTankovaniModal() {
      document.getElementById("tankovani-modal").classList.add("hidden");
      document.getElementById("tank-litry").value = "";
      document.getElementById("tank-tachometr").value = "";
      document.getElementById("tank-do-plna").checked = true;
    }
  
    document.getElementById("tank-zrusit").onclick = zavriTankovaniModal;  
  
    document.getElementById("tank-ulozit").onclick = () => {
      const litry = parseFloat(
        document.getElementById("tank-litry").value.replace(",", ".")
      );
    
      const tach = parseInt(
        document.getElementById("tank-tachometr").value
      );
    
      const doPlna =
        document.getElementById("tank-do-plna").checked;
    
      if (isNaN(litry) || litry <= 0) {
        alert("Zadej platné množství litrů.");
        return;
      }
    
      if (isNaN(tach)) {
        alert("Zadej platný tachometr.");
        return;
      }
    
      const kapacita = parseFloat(localStorage.getItem("nadrz_l")) || 85;
      const spotreba = parseFloat(localStorage.getItem("spotreba")) || 0;
      const staryStav = parseFloat(localStorage.getItem("stav_v_nadrzi_l")) || 0;
      const posledniTach =
        parseInt(localStorage.getItem("predchoziTach")) ||
        parseInt(localStorage.getItem("lastTach")) ||
        tach;
    
      let stavPredTankovanim = staryStav;
    
      if (spotreba && tach >= posledniTach) {
        const kmOdPoslednihoBodu = tach - posledniTach;
        const spaleno = (kmOdPoslednihoBodu * spotreba) / 100;
        stavPredTankovanim = staryStav - spaleno;
      }
    
      let novyStav;
    
      if (doPlna) {
        novyStav = kapacita;
      } else {
        novyStav = stavPredTankovanim + litry;
        if (novyStav > kapacita) novyStav = kapacita;
      }
    
      novyStav = Math.round(novyStav * 2) / 2;
    
      localStorage.setItem("stav_v_nadrzi_l", novyStav);
      localStorage.setItem("predchoziTach", tach);
      localStorage.setItem("tankTach", tach);
    
      const puvodniLitry =
        parseFloat(localStorage.getItem("natankovano_l")) || 0;
    
      localStorage.setItem(
        "natankovano_l",
        puvodniLitry + litry
      );
    
      aktualizujStavPalivaVHlavicce();
    
      zavriTankovaniModal();
    
      alert(
        `Tankování uloženo.\n\n` +
        `Nový stav nádrže: ${novyStav} l`
      );
    };
  
    zobrazZaznamy();
    aktualizujTachometrVHlavicce();
    prepocitejStavPaliva();
  });

← Zpět na seznam