Skip to main content

SOURCE CODE: JOBs DONE REPORT versi MOBILE-PURPOSE aka +Bootstrap

 <!-- ============================================== -->

<!-- BOOTSTRAP CSS (BLOGGER-SAFE VERSION) -->

<!-- ============================================== -->

<link rel="stylesheet"

 href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"/>


<!-- ============================================== -->

<!-- FIREBASE (BLOGGER-SAFE VERSION) -->

<!-- ============================================== -->

<script src="https://www.gstatic.com/firebasejs/9.22.2/firebase-app-compat.js"></script>

<script src="https://www.gstatic.com/firebasejs/9.22.2/firebase-database-compat.js"></script>


<script>

firebase.initializeApp({

  apiKey: "AIzaSyAF5r6Rvu-DmoV-vf47wYTZfarpVGmNYR0",

  authDomain: "ronin-11938.firebaseapp.com",

  databaseURL: "https://ronin-11938-default-rtdb.firebaseio.com",

  projectId: "ronin-11938",

  storageBucket: "ronin-11938.firebasestorage.app",

  messagingSenderId: "823368889742",

  appId: "1:823368889742:web:609e16ace214b94a0df"

});

var dbRef = firebase.database().ref("JobDoneData");

</script>


<!-- ============================================== -->

<!-- MOBILE-FIRST RESPONSIVE CSS (BLOGGER SAFE) -->

<!-- ============================================== -->

<style>

@media (max-width: 575px) {

  .desktop-view { display:none !important; }

  .mobile-view { display:block !important; }

}

@media (min-width: 576px) {

  .desktop-view { display:block !important; }

  .mobile-view { display:none !important; }

}


.date-month {

  font-weight: bold;

  font-size: 1.05rem;

  display: block;

}

.date-year {

  display: block;

  margin-top: -4px;

  font-size: 0.85rem;

  color: #666;

}


.icon-btn {

  font-size: 22px;

  cursor: pointer;

  margin-right: 10px;

}


.glass-modal {

  position:fixed; left:0; top:0;

  width:100%; height:100%;

  background:rgba(0,0,0,0.55);

  display:none; justify-content:center; align-items:center;

  z-index:9999;

}

.glass-modal-content {

  background:white;

  padding:20px; border-radius:12px;

  width:90%; max-width:420px;

}

</style>


<!-- ============================================== -->

<!-- ADD NEW RECORD (BOOTSTRAP FORM) -->

<!-- ============================================== -->

<div class="container my-3">

  <div class="card shadow-sm">

    <div class="card-body">

      <h4 class="mb-3">➕ Add Job Done</h4>


      <label class="form-label fw-bold">Month</label>

      <select id="monthSelect" class="form-select mb-3"></select>


      <label class="form-label fw-bold">Year</label>

      <select id="yearSelect" class="form-select mb-3"></select>


      <label class="form-label fw-bold">Description</label>

      <textarea id="jobDesc" class="form-control mb-3" rows="3"></textarea>


      <button onclick="addRecord()" class="btn btn-primary w-100">💾 Save</button>

    </div>

  </div>

</div>


<!-- ============================================== -->

<!-- SEARCH + SORT -->

<!-- ============================================== -->

<div class="container my-3">

  <div class="card shadow-sm">

    <div class="card-body">


      <label class="form-label fw-bold">Search</label>

      <input id="searchInput" onkeyup="renderAll()" class="form-control mb-3" placeholder="Search…"/>


      <label class="form-label fw-bold">Sort</label>

      <select id="sortSelect" onchange="renderAll()" class="form-select">

        <option value="desc">Newest First</option>

        <option value="asc">Oldest First</option>

      </select>


    </div>

  </div>

</div>


<!-- ============================================== -->

<!-- DESKTOP TABLE -->

<!-- ============================================== -->

<div class="container desktop-view my-3">

  <div class="card shadow-sm">

    <div class="card-body">


      <table class="table table-striped align-middle">

        <thead>

          <tr>

            <th width="150">Date</th>

            <th>Description</th>

            <th width="100">Action</th>

          </tr>

        </thead>

        <tbody id="tableList"></tbody>

      </table>


    </div>

  </div>

</div>


<!-- ============================================== -->

<!-- MOBILE CARD VIEW -->

<!-- ============================================== -->

<div class="container mobile-view my-3" id="cardList"></div>


<!-- ============================================== -->

<!-- MODAL -->

<!-- ============================================== -->

<div id="modalGlass" class="glass-modal">

  <div class="glass-modal-content">

    <h4 id="modalTitle"></h4>

    <div id="modalBody" class="mt-2"></div>

    <button onclick="closeModal()" class="btn btn-secondary w-100 mt-3">Close</button>

  </div>

</div>


<!-- ============================================== -->

<!-- LOGIC SCRIPT -->

<!-- ============================================== -->

<script>

var allData = [];

var monthNames = [

  "January","February","March","April","May","June",

  "July","August","September","October","November","December"

];


function loadMonthYear() {

  var mSel = document.getElementById("monthSelect");

  var ySel = document.getElementById("yearSelect");


  var now = new Date();

  var curM = now.getMonth() + 1;

  var curY = now.getFullYear();


  for (var i=1;i<=12;i++) {

    var opt = document.createElement("option");

    opt.value = i;

    opt.text = monthNames[i-1];

    if (i === curM) opt.selected = true;

    mSel.appendChild(opt);

  }


  for (var y=2023;y<=curY+5;y++) {

    var opt2 = document.createElement("option");

    opt2.value = y;

    opt2.text = y;

    if (y === curY) opt2.selected = true;

    ySel.appendChild(opt2);

  }

}

loadMonthYear();


function addRecord() {

  var m = document.getElementById("monthSelect").value;

  var y = document.getElementById("yearSelect").value;

  var d = document.getElementById("jobDesc").value.trim();


  if (!m || !y || !d) { alert("Please fill all fields"); return; }


  var id = dbRef.push().key;


  dbRef.child(id).set({

    id:id,

    month:parseInt(m),

    year:parseInt(y),

    description:d,

    sortKey:(parseInt(y)*100)+parseInt(m)

  });


  document.getElementById("jobDesc").value = "";

}


dbRef.on("value", function(snap){

  allData = [];

  snap.forEach(function(c){ allData.push(c.val()); });

  renderAll();

});


function renderAll(){

  renderTable();

  renderCards();

}


function renderTable(){

  var tbody = document.getElementById("tableList");

  tbody.innerHTML = "";

  var list = filteredSorted();


  for (var i=0;i<list.length;i++){

    var r=list[i];

    var tr=document.createElement("tr");


    tr.innerHTML = `

      <td>

        <span class="date-month">${monthNames[r.month-1]}</span>

        <span class="date-year">${r.year}</span>

      </td>

      <td>${r.description.replace(/\n/g,"<br>")}</td>

      <td>

        <span class="icon-btn" onclick="viewRec('${r.id}')">👁️</span>

        <span class="icon-btn" onclick="editRec('${r.id}')">✏️</span>

        <span class="icon-btn" onclick="delRec('${r.id}')">🗑️</span>

      </td>

    `;


    tbody.appendChild(tr);

  }

}


function renderCards(){

  var wrap = document.getElementById("cardList");

  wrap.innerHTML = "";

  var list = filteredSorted();


  for (var i=0;i<list.length;i++){

    var r=list[i];

    var card=document.createElement("div");

    card.className="card p-3 mb-3 shadow-sm";


    card.innerHTML = `

      <h6><b>${monthNames[r.month-1]} ${r.year}</b></h6>

      <p>${r.description.replace(/\n/g,"<br>")}</p>

      <span class="icon-btn" onclick="viewRec('${r.id}')">👁️</span>

      <span class="icon-btn" onclick="editRec('${r.id}')">✏️</span>

      <span class="icon-btn" onclick="delRec('${r.id}')">🗑️</span>

    `;


    wrap.appendChild(card);

  }

}


function filteredSorted(){

  var s=document.getElementById("searchInput").value.toLowerCase();

  var st=document.getElementById("sortSelect").value;


  var arr=allData.filter(function(d){

    return (monthNames[d.month-1] + " " + d.year + " " + d.description)

      .toLowerCase().includes(s);

  });


  arr.sort(function(a,b){

    return st==="desc" ? b.sortKey-a.sortKey : a.sortKey-b.sortKey;

  });


  return arr;

}


/* RECORD ACTIONS */

function viewRec(id){

  var r=allData.find(function(x){return x.id===id;});

  if (!r) return;


  openModal(

    "View Record",

    monthNames[r.month-1]+" "+r.year+"\n\n"+r.description

  );

}


function editRec(id){

  var r=allData.find(function(x){return x.id===id;});

  if (!r) return;


  var newDesc = prompt("Edit description:", r.description);

  if (newDesc!==null){

    dbRef.child(id).update({description:newDesc});

  }

}


function delRec(id){

  if (confirm("Delete this record?")){

    dbRef.child(id).remove();

  }

}


/* MODAL CONTROL */

function openModal(t,b){

  document.getElementById("modalTitle").textContent=t;

  document.getElementById("modalBody").textContent=b;

  document.getElementById("modalGlass").style.display="flex";

}

function closeModal(){

  document.getElementById("modalGlass").style.display="none";

}

</script>


Comments