SOURCE CODE OF
"JOBs DONE REPORT" POST


TIPS PENTING!!
Terkadang aka maksud gw pada pembuatan POST ini ..
Ada tarik menarik pada Aspek COMPATIBILITY
TERUTAMA PADA ASPEK TAMPILAN
Sehingga gw buat POSTINGAN 2 VERSI:
Condong Compatible ke Web Browser dan Condong ke Android App
VERSI pada POST ini adalah Condong ke Web Browser

<!-- ============================================== -->
<!-- FIREBASE CDN (BLOGGER COMPAT MODE) -->
<!-- ============================================== -->
<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 rdb = firebase.database();
var refCRUD = rdb.ref("JobDoneData");
</script>

<!-- ============================================== -->
<!-- STYLE (BLOGGER SAFE) -->
<!-- ============================================== -->
<style>
:root {
  --bg: #ffffff;
  --card: #ffffff;
  --glass: rgba(255,255,255,0.82);
  --border: #dcdcdc;
  --shadow: rgba(0,0,0,0.14);
  --text: #222;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #111;
    --card: #1b1b1b;
    --glass: rgba(40,40,40,0.72);
    --border: #333;
    --shadow: rgba(0,0,0,0.55);
    --text: #f5f5f5;
  }
}
body { background: var(--bg); color: var(--text); }

.crud-box, .table-box {
  background: var(--card);
  border:1px solid var(--border);
  padding:18px;
  border-radius:12px;
  margin-bottom:20px;
  box-shadow:0 4px 12px var(--shadow);
}

input, select, textarea {
  padding:10px;
  width:100%;
  border-radius:8px;
  border:1px solid var(--border);
  box-shadow:0 1px 3px var(--shadow) inset;
}

.icon-btn {
  cursor:pointer;
  font-size:22px;
  margin-right:6px;
  transition:0.15s;
}
.icon-btn:hover { transform:scale(1.28); }

/* ========================================= */
/* NEW DATE COLUMN — TWO ROWS (Month + Year) */
/* ========================================= */
.date-cell {
  width: 150px;
  min-width: 150px;
  text-align: center;
  white-space: normal;
  line-height: 1.25;
  font-weight: 600;
}
.date-year {
  display:block;
  font-size:0.9em;
  margin-top:2px;
  color:#666;
}

.glass-modal {
  position:fixed; top:0; left:0; width:100%; height:100%;
  background:rgba(0,0,0,0.55);
  display:none;
  align-items:center;
  justify-content:center;
  z-index:9999;
}
.glass-modal-content {
  background:var(--glass);
  backdrop-filter:blur(12px);
  padding:20px;
  border-radius:15px;
  width:90%;
  max-width:420px;
  box-shadow:0 4px 18px var(--shadow);
  color:var(--text);
}

.table-clean { border-collapse:collapse; width:100%; }
.table-clean th {
  background:#eaeaea;
  padding:10px;
  border-bottom:2px solid var(--border);
}
.table-clean td {
  padding:10px;
  border-bottom:1px solid var(--border);
}
.table-clean tr:nth-child(even) {
  background:rgba(0,0,0,0.04);
}
</style>

<!-- ============================================== -->
<!-- INPUT FORM -->
<!-- ============================================== -->
<div class="crud-box">
  <h3>➕ Add Job Done</h3>

  <label><b>Month</b></label>
  <select id="monthSelect" style="margin-bottom:10px;"></select>

  <label><b>Year</b></label>
  <select id="yearSelect" style="margin-bottom:10px;"></select>

  <label><b>Description</b></label>
  <textarea id="jobDesc" style="height:80px;"></textarea>

  <br><br>
  <button onclick="addRecord()"
    style="padding:10px 20px; border-radius:8px; border:none; background:#007bff; color:white;">
    💾 Save
  </button>
</div>

<!-- ============================================== -->
<!-- SEARCH + SORT -->
<!-- ============================================== -->
<div class="crud-box">
  <label><b>Search</b></label>
  <input id="searchInput" onkeyup="renderTable()" placeholder="Search description or date…" />

  <br><br>

  <label><b>Sort by</b></label>
  <select id="sortSelect" onchange="renderTable()">
    <option value="desc">Newest First</option>
    <option value="asc">Oldest First</option>
  </select>
</div>

<!-- ============================================== -->
<!-- TABLE -->
<!-- ============================================== -->
<div class="table-box">
  <table class="table-clean">
    <thead>
      <tr>
        <th>Date</th>
        <th>Description</th>
        <th>Action</th>
      </tr>
    </thead>
    <tbody id="dataList"></tbody>
  </table>
</div>

<!-- ============================================== -->
<!-- CUSTOM FLOATING GLASS MODAL -->
<!-- ============================================== -->
<div id="modalGlass" class="glass-modal">
  <div class="glass-modal-content">
    <h4 id="modalTitle"></h4>
    <div id="modalBody" style="white-space:pre-wrap; margin-top:10px;"></div>
    <br>
    <button onclick="closeModal()" style="padding:8px 15px;">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 today = new Date();
  var curM = today.getMonth() + 1;
  var curY = today.getFullYear();

  for (var i=1; i<=12; i++) {
    var o = document.createElement("option");
    o.value = i;
    o.text = monthNames[i-1];
    if (i === curM) o.selected = true;
    mSel.appendChild(o);
  }

  for (var y=2023; y<=curY+5; y++) {
    var o2 = document.createElement("option");
    o2.value = y;
    o2.text = y;
    if (y === curY) o2.selected = true;
    ySel.appendChild(o2);
  }
}
loadMonthYear();

function addRecord() {
  var m = document.getElementById("monthSelect").value;
  var y = document.getElementById("yearSelect").value;
  var desc = document.getElementById("jobDesc").value;

  if (m==="" || y==="" || desc.trim()==="") {
    alert("Please complete all fields.");
    return;
  }

  var id = refCRUD.push().key;

  refCRUD.child(id).set({
    id:id,
    month:m,
    year:y,
    description:desc,
    sortKey:(parseInt(y)*100)+parseInt(m)
  });

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

refCRUD.on("value", function(snap) {
  allData=[];
  snap.forEach(function(c){ allData.push(c.val()); });
  renderTable();
});

function renderTable() {
  var tbody=document.getElementById("dataList");
  tbody.innerHTML="";

  var search=document.getElementById("searchInput").value.toLowerCase();
  var sort=document.getElementById("sortSelect").value;

  var filtered=[];
  for (var i=0;i<allData.length;i++){
    var text = monthNames[allData[i].month-1] + " " + allData[i].year + " " + allData[i].description;
    if (text.toLowerCase().indexOf(search)!==-1) filtered.push(allData[i]);
  }

  filtered.sort(function(a,b){
    return sort==="desc" ? b.sortKey-a.sortKey : a.sortKey-b.sortKey;
  });

  for (var i=0;i<filtered.length;i++){
    var d=filtered[i];
    var tr=document.createElement("tr");

    tr.innerHTML =
      "<td class='date-cell'>" +
         monthNames[d.month-1] +
         "<span class='date-year'>" + d.year + "</span>" +
      "</td>" +
      "<td>"+ d.description.replace(/\\n/g,'<br>') +"</td>" +
      "<td>" +
        "<span class='icon-btn' onclick=\"viewRecord('" + d.id + "')\">👁️</span>" +
        "<span class='icon-btn' onclick=\"editRecord('" + d.id + "')\">✏️</span>" +
        "<span class='icon-btn' onclick=\"deleteRecord('" + d.id + "')\">🗑️</span>" +
      "</td>";

    tbody.appendChild(tr);
  }
}

function viewRecord(id){
  for (var i=0;i<allData.length;i++){
    if (allData[i].id===id){
      openModal(
        "View Record",
        monthNames[allData[i].month-1]+" "+allData[i].year+"\n\n"+allData[i].description
      );
      return;
    }
  }
}

function editRecord(id){
  for (var i=0;i<allData.length;i++){
    if (allData[i].id===id){
      var newDesc=prompt("Edit description:", allData[i].description);
      if (newDesc!==null){
        refCRUD.child(id).update({description:newDesc});
      }
      return;
    }
  }
}

function deleteRecord(id){
  if (confirm("Delete this record?")){
    refCRUD.child(id).remove();
  }
}

function openModal(title,body){
  document.getElementById("modalTitle").textContent=title;
  document.getElementById("modalBody").textContent=body;
  document.getElementById("modalGlass").style.display="flex";
}

function closeModal(){
  document.getElementById("modalGlass").style.display="none";
}
</script>

Comments