diff --git a/Views/Website/Jasa/PengolahanSampah.cshtml b/Views/Website/Jasa/PengolahanSampah.cshtml index 1773cf2..1c04afe 100644 --- a/Views/Website/Jasa/PengolahanSampah.cshtml +++ b/Views/Website/Jasa/PengolahanSampah.cshtml @@ -285,35 +285,78 @@
-
-
-

Daftar Jasa Pengolahan Sampah

-

Data perusahaan yang memiliki izin pengolahan sampah di DKI Jakarta

+
+
+

Daftar Jasa Pengolahan Sampah

+

Data perusahaan yang memiliki izin pengolahan sampah di DKI Jakarta

-
- - - - - - - - - - - - -
NoPerusahaanAlamatBerlaku Hingga
-
- -
-
- - - - - Memuat data... +
+
+
+ + + data per halaman +
+ +
+ +
+ + + +
+
+
+ +
+
+ + + + + + + + + + + +
NoPerusahaanAlamatBerlaku Hingga
+
+ +
+
+ + + + + Memuat data... +
+
+ + +
+ +
+
+
+ +
diff --git a/wwwroot/website/css/watch.css b/wwwroot/website/css/watch.css index dbe1f04..436b5f1 100644 --- a/wwwroot/website/css/watch.css +++ b/wwwroot/website/css/watch.css @@ -85,17 +85,14 @@ --color-indigo-50: oklch(96.2% 0.018 272.314); --color-indigo-100: oklch(93% 0.034 272.788); --color-indigo-300: oklch(78.5% 0.115 274.713); - --color-indigo-800: oklch(39.8% 0.195 277.366); --color-purple-50: oklch(97.7% 0.014 308.299); --color-purple-100: oklch(94.6% 0.033 307.174); --color-purple-200: oklch(90.2% 0.063 306.703); --color-purple-500: oklch(62.7% 0.265 303.9); --color-purple-600: oklch(55.8% 0.288 302.321); - --color-purple-700: oklch(49.6% 0.265 301.924); --color-purple-800: oklch(43.8% 0.218 303.724); --color-purple-900: oklch(38.1% 0.176 304.987); --color-pink-50: oklch(97.1% 0.014 343.198); - --color-pink-500: oklch(65.6% 0.241 354.308); --color-rose-50: oklch(96.9% 0.015 12.422); --color-rose-500: oklch(64.5% 0.246 16.439); --color-rose-600: oklch(58.6% 0.253 17.585); @@ -117,9 +114,6 @@ --color-gray-700: oklch(37.3% 0.034 259.733); --color-gray-800: oklch(27.8% 0.033 256.848); --color-gray-900: oklch(21% 0.034 264.665); - --color-neutral-200: oklch(92.2% 0 0); - --color-neutral-600: oklch(43.9% 0 0); - --color-neutral-800: oklch(26.9% 0 0); --color-black: #000; --color-white: #fff; --spacing: 0.25rem; @@ -408,9 +402,6 @@ .top-0 { top: calc(var(--spacing) * 0); } - .top-1 { - top: calc(var(--spacing) * 1); - } .top-1\/2 { top: calc(1/2 * 100%); } @@ -465,9 +456,6 @@ .right-full { right: 100%; } - .-bottom-0 { - bottom: calc(var(--spacing) * -0); - } .-bottom-0\.5 { bottom: calc(var(--spacing) * -0.5); } @@ -504,9 +492,6 @@ .left-0 { left: calc(var(--spacing) * 0); } - .left-1 { - left: calc(var(--spacing) * 1); - } .left-1\/2 { left: calc(1/2 * 100%); } @@ -624,9 +609,6 @@ .col-span-2 { grid-column: span 2 / span 2; } - .col-span-12 { - grid-column: span 12 / span 12; - } .float-end { float: inline-end; } @@ -918,9 +900,6 @@ .aspect-video { aspect-ratio: var(--aspect-video); } - .h-0 { - height: calc(var(--spacing) * 0); - } .h-0\.5 { height: calc(var(--spacing) * 0.5); } @@ -1095,6 +1074,9 @@ .w-75 { width: calc(var(--spacing) * 75); } + .w-80 { + width: calc(var(--spacing) * 80); + } .w-100 { width: calc(var(--spacing) * 100); } @@ -1161,9 +1143,6 @@ .shrink { flex-shrink: 1; } - .shrink-0 { - flex-shrink: 0; - } .flex-grow { flex-grow: 1; } @@ -1185,16 +1164,9 @@ .border-collapse { border-collapse: collapse; } - .border-separate { - border-collapse: separate; - } .origin-top { transform-origin: top; } - .-translate-x-1 { - --tw-translate-x: calc(var(--spacing) * -1); - translate: var(--tw-translate-x) var(--tw-translate-y); - } .-translate-x-1\/2 { --tw-translate-x: calc(calc(1/2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); @@ -1207,10 +1179,6 @@ --tw-translate-x: calc(var(--spacing) * 16); translate: var(--tw-translate-x) var(--tw-translate-y); } - .-translate-y-1 { - --tw-translate-y: calc(var(--spacing) * -1); - translate: var(--tw-translate-x) var(--tw-translate-y); - } .-translate-y-1\/2 { --tw-translate-y: calc(calc(1/2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); @@ -1289,9 +1257,6 @@ .grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } - .grid-cols-12 { - grid-template-columns: repeat(12, minmax(0, 1fr)); - } .flex-col { flex-direction: column; } @@ -1397,6 +1362,13 @@ margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse))); } } + .space-x-1 { + :where(& > :not(:last-child)) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(calc(var(--spacing) * 1) * var(--tw-space-x-reverse)); + margin-inline-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-x-reverse))); + } + } .space-x-2 { :where(& > :not(:last-child)) { --tw-space-x-reverse: 0; @@ -1651,9 +1623,6 @@ border-color: color-mix(in oklab, var(--color-cyan-600) 50%, transparent); } } - .border-cyan-700 { - border-color: var(--color-cyan-700); - } .border-cyan-700\/50 { border-color: color-mix(in srgb, oklch(52% 0.105 223.128) 50%, transparent); @supports (color: color-mix(in lab, red, red)) { @@ -1693,9 +1662,6 @@ .border-green-400 { border-color: var(--color-green-400); } - .border-neutral-200 { - border-color: var(--color-neutral-200); - } .border-orange-200 { border-color: var(--color-orange-200); } @@ -1807,9 +1773,6 @@ .bg-blue-600 { background-color: var(--color-blue-600); } - .bg-current { - background-color: currentcolor; - } .bg-cyan-50 { background-color: var(--color-cyan-50); } @@ -1825,6 +1788,9 @@ .bg-cyan-500 { background-color: var(--color-cyan-500); } + .bg-cyan-600 { + background-color: var(--color-cyan-600); + } .bg-cyan-700 { background-color: var(--color-cyan-700); } @@ -2247,6 +2213,10 @@ --tw-gradient-to: var(--color-emerald-600); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); } + .to-gray-50 { + --tw-gradient-to: var(--color-gray-50); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } .to-gray-100 { --tw-gradient-to: var(--color-gray-100); --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); @@ -2571,6 +2541,9 @@ .pl-9 { padding-left: calc(var(--spacing) * 9); } + .pl-10 { + padding-left: calc(var(--spacing) * 10); + } .text-center { text-align: center; } @@ -2694,9 +2667,6 @@ .break-all { word-break: break-all; } - .whitespace-nowrap { - white-space: nowrap; - } .text-amber-400 { color: var(--color-amber-400); } @@ -2796,9 +2766,6 @@ .text-green-900 { color: var(--color-green-900); } - .text-neutral-800 { - color: var(--color-neutral-800); - } .text-orange-100 { color: var(--color-orange-100); } @@ -2826,6 +2793,9 @@ .text-purple-900 { color: var(--color-purple-900); } + .text-red-400 { + color: var(--color-red-400); + } .text-red-500 { color: var(--color-red-500); } @@ -3085,10 +3055,6 @@ --tw-outline-style: none; outline-style: none; } - .select-all { - -webkit-user-select: all; - user-select: all; - } .select-none { -webkit-user-select: none; user-select: none; @@ -3228,6 +3194,13 @@ } } } + .hover\:border-cyan-300 { + &:hover { + @media (hover: hover) { + border-color: var(--color-cyan-300); + } + } + } .hover\:border-cyan-400 { &:hover { @media (hover: hover) { @@ -3284,6 +3257,13 @@ } } } + .hover\:bg-cyan-50 { + &:hover { + @media (hover: hover) { + background-color: var(--color-cyan-50); + } + } + } .hover\:bg-cyan-500 { &:hover { @media (hover: hover) { @@ -3298,6 +3278,13 @@ } } } + .hover\:bg-cyan-700 { + &:hover { + @media (hover: hover) { + background-color: var(--color-cyan-700); + } + } + } .hover\:bg-gray-50 { &:hover { @media (hover: hover) { @@ -3700,6 +3687,20 @@ max-width: var(--container-md); } } + .sm\:flex-row { + @media (width >= 40rem) { + flex-direction: row; + } + } + .sm\:space-y-0 { + @media (width >= 40rem) { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 0) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 0) * calc(1 - var(--tw-space-y-reverse))); + } + } + } .sm\:space-y-6 { @media (width >= 40rem) { :where(& > :not(:last-child)) { @@ -3709,6 +3710,15 @@ } } } + .sm\:space-x-4 { + @media (width >= 40rem) { + :where(& > :not(:last-child)) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(calc(var(--spacing) * 4) * var(--tw-space-x-reverse)); + margin-inline-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-x-reverse))); + } + } + } .sm\:rounded-3xl { @media (width >= 40rem) { border-radius: var(--radius-3xl); @@ -3972,16 +3982,6 @@ padding-inline: calc(var(--spacing) * 8); } } - .dark\:border-neutral-600 { - @media (prefers-color-scheme: dark) { - border-color: var(--color-neutral-600); - } - } - .dark\:text-white { - @media (prefers-color-scheme: dark) { - color: var(--color-white); - } - } } @property --tw-translate-x { syntax: "*"; diff --git a/wwwroot/website/js/datatables_pengolahan.js b/wwwroot/website/js/datatables_pengolahan.js index fb58325..f62d8b3 100644 --- a/wwwroot/website/js/datatables_pengolahan.js +++ b/wwwroot/website/js/datatables_pengolahan.js @@ -1,353 +1,523 @@ -document.addEventListener("DOMContentLoaded", function () { - initializePengolahanDataTable(); -}); +class CustomTable { + constructor(tableId, apiUrl) { + this.tableId = tableId; + this.apiUrl = apiUrl; + this.currentPage = 1; + this.pageSize = 10; + this.draw = 1; + this.searchTerm = ""; + this.totalRecords = 0; + this.filteredRecords = 0; + this.data = []; + this.isLoading = false; + this.paginationClickTimeout = null; -// helper: parse date string in format dd/mm/yyyy to a Date object (local) -function parseDateDMY(dateStr) { - if (!dateStr) return new Date(dateStr); - // accept either dd/mm/yyyy or ISO - if (dateStr.indexOf("/") !== -1) { - const parts = dateStr.split("/"); - // parts[0]=dd, [1]=mm, [2]=yyyy - const d = parseInt(parts[0], 10); - const m = parseInt(parts[1], 10) - 1; - const y = parseInt(parts[2], 10); - return new Date(y, m, d); + this.init(); } - return new Date(dateStr); -} -function initializePengolahanDataTable() { - if (!document.getElementById("pengolahanTable")) return; + init() { + this.injectStyles(); + this.createTableStructure(); + this.createPaginationControls(); + this.createSearchInput(); + this.bindEvents(); + this.loadData(); + } - if (typeof $ !== "undefined" && $.fn.DataTable) { - $("#pengolahanTable").DataTable({ - ajax: { - url: "/api/web/jasa/olah", - type: "POST", - dataSrc: function (json) { - if (!json) return []; - return json.data || json; - }, - error: function (xhr, error, thrown) { - console.error("Error fetching pengolahan data:", error || thrown); - }, - }, - columns: [ - { - data: null, - className: "px-3 py-4 text-sm text-gray-900 text-center font-medium", - title: "No", - width: "5%", - render: function (data, type, row, meta) { - return meta.row + 1; - }, - }, - { - data: "nama", - className: "px-3 py-4 text-sm text-gray-900 font-medium break-words", - title: "Nama Perusahaan", - width: "25%", - }, - { - data: "alamat", - className: "px-3 py-4 text-sm text-gray-700 break-words", - title: "Alamat", - width: "50%", - }, - { - data: "tglBerlakuIzin", - className: "px-3 py-4 text-sm text-gray-900 text-center", - title: "Berlaku Hingga", - width: "20%", - render: function (data, type, row) { - if (type === "display") { - const date = parseDateDMY(data); - const formattedDate = date.toLocaleDateString("id-ID", { - year: "numeric", - month: "2-digit", - day: "2-digit", - }); - - const today = new Date(); - const expiry = parseDateDMY(data); - const daysUntilExpiry = Math.ceil( - (expiry - today) / (1000 * 60 * 60 * 24) - ); - - let statusClass = "bg-green-100 text-green-800"; - if (daysUntilExpiry < 30) { - statusClass = "bg-red-100 text-red-800"; - } else if (daysUntilExpiry < 90) { - statusClass = "bg-yellow-100 text-yellow-800"; - } - - return `
-
${formattedDate}
- - ${ - daysUntilExpiry > 0 - ? `${daysUntilExpiry} hari` - : "Expired" - } - -
`; + injectStyles() { + const styles = ` + + `; - const wrapper = $(".dataTables_wrapper"); + const existingStyles = document.getElementById("custom-table-styles"); + if (existingStyles) { + existingStyles.remove(); + } + document.head.insertAdjacentHTML("beforeend", styles); + } - wrapper - .find('input[type="search"]') - .addClass( - "block w-full px-4 py-2 text-sm border border-gray-300 rounded-lg bg-white focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" - ) - .attr("placeholder", "Cari perusahaan pengolahan..."); + createTableStructure() { + const table = document.getElementById(this.tableId); + table.classList.add("modern-table"); - wrapper - .find("select") - .addClass( - "px-3 py-2 text-sm border border-gray-300 rounded-lg bg-white focus:ring-2 focus:ring-blue-500 focus:border-transparent" - ); + let tbody = table.querySelector("tbody"); + if (tbody) { + tbody.id = `${this.tableId}-tbody`; + } - wrapper - .find(".dt-paging .dt-paging-button") - .addClass( - "px-3 py-2 mx-1 text-sm border border-gray-300 rounded-md bg-white text-gray-700 hover:bg-blue-50 hover:text-blue-600 hover:border-blue-300 transition-all duration-200" - ); + this.showLoading(); + } - wrapper - .find(".dt-paging .dt-paging-button.current") - .addClass("bg-blue-600 text-white border-blue-600 hover:bg-blue-700") - .removeClass("bg-white text-gray-700"); + createSearchInput() {} - wrapper - .find(".dt-paging .dt-paging-button.disabled") - .addClass("opacity-50 cursor-not-allowed"); + createPaginationControls() {} - if (window.innerWidth <= 768) { - wrapper.find(".dt-paging").addClass("text-center"); - wrapper.find(".dt-info").addClass("text-center text-sm"); - wrapper.find(".dt-length").addClass("text-center"); - wrapper.find(".dt-search").addClass("text-center"); + bindEvents() { + const searchInput = document.getElementById("searchInput"); + const pageSizeSelect = document.getElementById("perPage"); + + if (searchInput) { + searchInput.addEventListener("keypress", (e) => { + if (e.key === "Enter") { + this.searchTerm = searchInput.value; + this.currentPage = 1; + this.draw++; + this.loadData(); } + }); - wrapper.find(".dt-length").addClass("flex items-center space-x-2"); - wrapper.find(".dt-search").addClass("flex items-center space-x-2"); - wrapper.find(".dt-info").addClass("text-sm text-gray-600"); + searchInput.addEventListener("input", (e) => { + clearTimeout(this.searchTimeout); + this.searchTimeout = setTimeout(() => { + this.searchTerm = searchInput.value; + this.currentPage = 1; + this.draw++; + this.loadData(); + }, 500); + }); + } - $("#pengolahanTable").removeClass("dataTable").addClass("w-full"); - $("#pengolahanTable thead th").addClass( - "bg-cyan-400 text-white font-semibold text-sm uppercase tracking-wider border-b" - ); - - wrapper.find(".dtr-control").remove(); - - $("#pengolahanTable tbody tr").addClass("transition-all duration-200"); - - $(window).on("resize", function () { - const wrapper = $(".dataTables_wrapper"); - if (window.innerWidth <= 768) { - wrapper.find(".dt-paging").addClass("text-center"); - wrapper.find(".dt-info").addClass("text-center text-sm"); - wrapper.find(".dt-length").addClass("text-center"); - wrapper.find(".dt-search").addClass("text-center"); - } else { - wrapper.find(".dt-paging").removeClass("text-center"); - wrapper.find(".dt-info").removeClass("text-center text-sm"); - wrapper.find(".dt-length").removeClass("text-center"); - wrapper.find(".dt-search").removeClass("text-center"); - } - }); - }, - drawCallback: function () { - $("#pengolahanTable tbody tr") - .removeClass("bg-blue-50") - .hover( - function () { - $(this).addClass( - "bg-blue-50 shadow-sm transform transition-all duration-200" - ); - }, - function () { - $(this).removeClass("bg-blue-50 shadow-sm transform"); - } - ); - - $("#pengolahanTable tbody tr:even").addClass("bg-gray-50"); - $("#pengolahanTable tbody tr:odd").addClass("bg-white"); - }, - }); - } else { - loadPengolahanDataManually(); + if (pageSizeSelect) { + pageSizeSelect.addEventListener("change", (e) => { + this.pageSize = parseInt(e.target.value); + this.currentPage = 1; + this.draw++; + this.loadData(); + }); + } } -} -function loadPengolahanDataManually() { - fetch("/website/data/pengolahan-data.json") - .then((response) => { + async loadData() { + if (this.isLoading) { + console.log("Already loading, skipping..."); + return; + } + + console.log("Starting loadData...", { + currentPage: this.currentPage, + pageSize: this.pageSize, + searchTerm: this.searchTerm, + draw: this.draw, + }); + + this.isLoading = true; + this.showLoading(); + + try { + const start = (this.currentPage - 1) * this.pageSize; + + const formData = new URLSearchParams(); + formData.append("draw", this.draw.toString()); + formData.append("start", start.toString()); + formData.append("length", this.pageSize.toString()); + + if (this.searchTerm) { + formData.append("search[value]", this.searchTerm); + } + + const response = await fetch(this.apiUrl, { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + body: formData, + }); + if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } - return response.json(); - }) - .then((data) => { - const tbody = document.querySelector("#pengolahanTable tbody"); - tbody.innerHTML = ""; - data.forEach((item, index) => { - const row = document.createElement("tr"); - row.className = `${ - index % 2 === 0 ? "bg-gray-50" : "bg-white" - } hover:bg-blue-50 transition-all duration-200`; + const result = await response.json(); - const date = parseDateDMY(item.tglBerlakuIzin); - const formattedDate = date.toLocaleDateString("id-ID", { - year: "numeric", - month: "2-digit", - day: "2-digit", - }); + this.data = result.data || []; + this.totalRecords = result.recordsTotal || 0; + this.filteredRecords = result.recordsFiltered || 0; - const today = new Date(); - const expiry = new Date(item.tglBerlakuIzin); - const daysUntilExpiry = Math.ceil( - (expiry - today) / (1000 * 60 * 60 * 24) - ); - - let statusClass = "bg-green-100 text-green-800"; - let statusText = `${daysUntilExpiry} hari`; - - if (daysUntilExpiry < 0) { - statusClass = "bg-red-100 text-red-800"; - statusText = "Expired"; - } else if (daysUntilExpiry < 30) { - statusClass = "bg-red-100 text-red-800"; - } else if (daysUntilExpiry < 90) { - statusClass = "bg-yellow-100 text-yellow-800"; - } - - row.innerHTML = ` - ${ - index + 1 - } - ${ - item.nama - } - ${ - item.alamat - } - -
${formattedDate}
- - ${statusText} - - - `; - - tbody.appendChild(row); + console.log("Data loaded successfully:", { + dataLength: this.data.length, + totalRecords: this.totalRecords, + filteredRecords: this.filteredRecords, }); - const loadingIndicator = document.getElementById("loadingIndicator"); - if (loadingIndicator) { - loadingIndicator.style.display = "none"; - } - - addManualSearch(data); - }) - .catch((error) => { + this.renderTable(); + this.renderPagination(); + this.hideLoading(); + } catch (error) { console.error("Error loading data:", error); - const loadingIndicator = document.getElementById("loadingIndicator"); - if (loadingIndicator) { - loadingIndicator.innerHTML = ` -
- - Error memuat data: ${error.message} -
- `; - } - }); -} + this.showError("Gagal memuat data. Silakan coba lagi."); + } finally { + this.isLoading = false; + } + } -function addManualSearch(data) { - const tableContainer = document - .querySelector("#pengolahanTable") - .closest(".bg-white"); - if (!document.getElementById("manualSearchInput")) { - const searchContainer = document.createElement("div"); - searchContainer.className = "mb-4 flex justify-end"; - searchContainer.innerHTML = ` -
- -
- - - -
-
- `; + showLoading() { + const loadingIndicator = document.getElementById("loadingIndicator"); + const emptyState = document.getElementById("emptyState"); + const tableContainer = document.querySelector(".overflow-x-auto"); + const pagination = document.getElementById("pagination"); - tableContainer.insertBefore( - searchContainer, - document.querySelector(".overflow-x-auto") - ); + if (loadingIndicator) loadingIndicator.classList.remove("hidden"); + if (emptyState) emptyState.classList.add("hidden"); + if (tableContainer) tableContainer.style.display = "none"; - document - .getElementById("manualSearchInput") - .addEventListener("input", function (e) { - const searchTerm = e.target.value.toLowerCase(); - const rows = document.querySelectorAll("#pengolahanTable tbody tr"); - - rows.forEach((row) => { - const text = row.textContent.toLowerCase(); - if (text.includes(searchTerm)) { - row.style.display = ""; - } else { - row.style.display = "none"; - } - }); + if (pagination) { + const buttons = pagination.querySelectorAll("button"); + buttons.forEach((btn) => { + btn.style.opacity = "0.5"; + btn.style.pointerEvents = "none"; }); + } + } + + showError(message) { + const loadingIndicator = document.getElementById("loadingIndicator"); + const emptyState = document.getElementById("emptyState"); + const tableContainer = document.querySelector(".overflow-x-auto"); + + if (loadingIndicator) { + loadingIndicator.classList.add("hidden"); + } + if (emptyState) { + emptyState.classList.remove("hidden"); + emptyState.innerHTML = ` +
+
+ +
+

${message}

+
+ `; + } + if (tableContainer) tableContainer.style.display = "none"; + } + + hideLoading() { + const loadingIndicator = document.getElementById("loadingIndicator"); + const emptyState = document.getElementById("emptyState"); + const tableContainer = document.querySelector(".overflow-x-auto"); + const pagination = document.getElementById("pagination"); + + if (loadingIndicator) loadingIndicator.classList.add("hidden"); + if (emptyState) emptyState.classList.add("hidden"); + if (tableContainer) tableContainer.style.display = "block"; + + if (pagination) { + const buttons = pagination.querySelectorAll("button"); + buttons.forEach((btn) => { + if (!btn.hasAttribute("disabled")) { + btn.style.opacity = "1"; + btn.style.pointerEvents = "auto"; + } + }); + } + } + + renderTable() { + const tbody = + document.querySelector(`#${this.tableId} tbody`) || + document.getElementById(`${this.tableId}-tbody`); + const emptyState = document.getElementById("emptyState"); + const tableContainer = document.querySelector(".overflow-x-auto"); + + if (this.data.length === 0) { + if (tableContainer) tableContainer.style.display = "none"; + if (emptyState) emptyState.classList.remove("hidden"); + this.updateTableInfo(); + this.renderPagination(); + return; + } + + if (tableContainer) tableContainer.style.display = "block"; + if (emptyState) emptyState.classList.add("hidden"); + + const start = (this.currentPage - 1) * this.pageSize; + let html = ""; + + this.data.forEach((row, index) => { + const no = start + index + 1; + const dateInfo = this.formatDate(row.tglBerlakuIzin); + + html += ` + + ${no} + +
${this.escapeHtml( + row.nama || "-" + )}
+ + +
${this.escapeHtml( + row.alamat || "-" + )}
+ + +
+
${ + dateInfo.formatted + }
+ + ${dateInfo.statusText} + +
+ + + `; + }); + + tbody.innerHTML = html; + + this.updateTableInfo(); + } + + renderPagination() { + const container = document.getElementById("pagination"); + const totalPages = Math.ceil(this.filteredRecords / this.pageSize); + + if (!container) return; + + let paginationHtml = ""; + + paginationHtml += ` + + `; + + const startPage = Math.max(1, this.currentPage - 2); + const endPage = Math.min(totalPages, this.currentPage + 2); + + if (startPage > 1) { + paginationHtml += ``; + if (startPage > 2) { + paginationHtml += `...`; + } + } + + for (let i = startPage; i <= endPage; i++) { + paginationHtml += ` + + `; + } + + if (endPage < totalPages) { + if (endPage < totalPages - 1) { + paginationHtml += `...`; + } + paginationHtml += ``; + } + + paginationHtml += ` + + `; + + container.innerHTML = paginationHtml; + + if (container._clickHandler) { + container.removeEventListener("click", container._clickHandler); + } + if (container._touchHandler) { + container.removeEventListener("touchstart", container._touchHandler); + } + if (container._touchEndHandler) { + container.removeEventListener("touchend", container._touchEndHandler); + } + + container._clickHandler = (e) => { + e.preventDefault(); + e.stopPropagation(); + + console.log("Pagination clicked:", e.target); + + let clickedButton = e.target; + if (e.target.tagName === "SVG" || e.target.tagName === "PATH") { + clickedButton = e.target.closest("button"); + } + + if ( + clickedButton && + clickedButton.tagName === "BUTTON" && + clickedButton.dataset.page + ) { + console.log("Button clicked:", { + page: clickedButton.dataset.page, + disabled: clickedButton.disabled, + hasAttribute: clickedButton.hasAttribute("disabled"), + }); + + const page = parseInt(clickedButton.dataset.page); + + if ( + page && + page !== this.currentPage && + page >= 1 && + page <= totalPages && + !clickedButton.disabled && + !clickedButton.hasAttribute("disabled") && + !this.isLoading + ) { + console.log("Navigating to page:", page); + + if (this.paginationClickTimeout) { + clearTimeout(this.paginationClickTimeout); + } + + this.paginationClickTimeout = setTimeout(() => { + this.currentPage = page; + this.draw++; + this.loadData(); + }, 100); + } else { + console.log("Click ignored:", { + samePage: page === this.currentPage, + outOfRange: page < 1 || page > totalPages, + disabled: + clickedButton.disabled || clickedButton.hasAttribute("disabled"), + loading: this.isLoading, + }); + } + } + }; + + container._touchHandler = (e) => { + e.preventDefault(); + e.stopPropagation(); + }; + + container.addEventListener("click", container._clickHandler); + container.addEventListener("touchstart", container._touchHandler, { + passive: false, + }); + + container._touchEndHandler = (e) => { + e.preventDefault(); + e.stopPropagation(); + }; + container.addEventListener("touchend", container._touchEndHandler, { + passive: false, + }); + } + + updateTableInfo() { + const infoContainer = document.getElementById("tableInfo"); + if (infoContainer) { + const start = (this.currentPage - 1) * this.pageSize + 1; + const end = Math.min( + this.currentPage * this.pageSize, + this.filteredRecords + ); + infoContainer.innerHTML = `Menampilkan ${start} hingga ${end} dari ${this.filteredRecords} data`; + } + } + + formatDate(dateString) { + if (!dateString || dateString === "0001-01-01") { + return { + formatted: "-", + statusClass: "bg-gray-100 text-gray-800", + statusText: "Tidak diketahui", + }; + } + + try { + const date = new Date(dateString); + const formattedDate = date.toLocaleDateString("id-ID", { + year: "numeric", + month: "2-digit", + day: "2-digit", + }); + + const today = new Date(); + const daysUntilExpiry = Math.ceil((date - today) / (1000 * 60 * 60 * 24)); + + let statusClass = "bg-green-100 text-green-800"; + let statusText = `${daysUntilExpiry} hari`; + + if (daysUntilExpiry < 0) { + statusClass = "bg-red-100 text-red-800"; + statusText = "Expired"; + } else if (daysUntilExpiry < 30) { + statusClass = "bg-red-100 text-red-800"; + } else if (daysUntilExpiry < 90) { + statusClass = "bg-yellow-100 text-yellow-800"; + } + + return { + formatted: formattedDate, + statusClass: statusClass, + statusText: statusText, + }; + } catch (error) { + return { + formatted: dateString, + statusClass: "bg-gray-100 text-gray-800", + statusText: "Invalid", + }; + } + } + + escapeHtml(text) { + const div = document.createElement("div"); + div.textContent = text; + return div.innerHTML; } } + +document.addEventListener("DOMContentLoaded", function () { + const tableElement = document.getElementById("pengolahanTable"); + if (tableElement && !tableElement.customTableInitialized) { + tableElement.customTableInitialized = true; + console.log("Initializing CustomTable..."); + new CustomTable( + "pengolahanTable", + "https://pesapakawan.dinaslhdki.id/api/web/jasa/olah" + ); + } +});