313 lines
11 KiB
JavaScript
313 lines
11 KiB
JavaScript
import { Grid, html } from "gridjs";
|
|
import { addThousandSeparators } from "../global-config";
|
|
|
|
class PublicSearch {
|
|
constructor() {
|
|
this.table = null;
|
|
const baseInput = document.getElementById("base_url_datatable");
|
|
this.baseUrl = baseInput ? baseInput.value.split("?")[0] : "";
|
|
this.keywordInput = document.getElementById("search_input");
|
|
this.searchButton = document.getElementById("search_button");
|
|
this.searchHeader = document.getElementById("search-header");
|
|
this.tableWrapper = document.getElementById("table-wrapper");
|
|
this.emptyState = document.getElementById("empty-state");
|
|
|
|
// Tidak inisialisasi datatable sampai ada pencarian
|
|
this.datatableUrl = null;
|
|
}
|
|
|
|
init() {
|
|
this.bindSearchButton();
|
|
|
|
// Check if there's a keyword in URL
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const keyword = urlParams.get("keyword");
|
|
|
|
if (keyword && keyword.trim() !== "") {
|
|
this.keywordInput.value = keyword.trim();
|
|
this.handleSearchFromUrl(keyword.trim());
|
|
}
|
|
}
|
|
|
|
handleSearchFromUrl(keyword) {
|
|
// Validasi input kosong atau hanya spasi
|
|
if (!keyword || keyword.trim().length === 0) {
|
|
this.showEmptyState("Mulai Pencarian");
|
|
return;
|
|
}
|
|
|
|
// Validasi minimal 3 karakter
|
|
if (keyword.trim().length < 3) {
|
|
this.showEmptyState("Minimal 3 karakter untuk pencarian");
|
|
return;
|
|
}
|
|
|
|
this.datatableUrl = this.buildUrl(keyword.trim());
|
|
this.showSearchResults();
|
|
this.initDatatable();
|
|
}
|
|
|
|
bindSearchButton() {
|
|
const handleSearch = () => {
|
|
const newKeyword = this.keywordInput.value.trim();
|
|
|
|
// Validasi input kosong atau hanya spasi
|
|
if (!newKeyword || newKeyword.length === 0) {
|
|
this.showEmptyState("Mulai Pencarian");
|
|
return;
|
|
}
|
|
|
|
// Validasi minimal 3 karakter (setelah trim)
|
|
if (newKeyword.length < 3) {
|
|
this.showEmptyState("Minimal 3 karakter untuk pencarian");
|
|
return;
|
|
}
|
|
|
|
// 1. Update datatable URL and reload
|
|
this.datatableUrl = this.buildUrl(newKeyword);
|
|
this.showSearchResults();
|
|
this.initDatatable();
|
|
|
|
// 2. Update URL query string (tanpa reload page)
|
|
const newUrl = `${window.location.pathname}${
|
|
newKeyword ? `?keyword=${encodeURIComponent(newKeyword)}` : ""
|
|
}`;
|
|
window.history.pushState({ path: newUrl }, "", newUrl);
|
|
|
|
// 3. Update visible keyword text di <em>{{ $keyword }}</em>>
|
|
const keywordDisplay = document.querySelector(".qs-header em");
|
|
if (keywordDisplay) {
|
|
keywordDisplay.textContent = newKeyword || "-";
|
|
}
|
|
};
|
|
|
|
this.searchButton.addEventListener("click", handleSearch);
|
|
|
|
this.keywordInput.addEventListener("keydown", (event) => {
|
|
if (event.key === "Enter") {
|
|
event.preventDefault();
|
|
handleSearch();
|
|
}
|
|
});
|
|
|
|
// Handle input change untuk real-time validation
|
|
this.keywordInput.addEventListener("input", (event) => {
|
|
const value = event.target.value.trim();
|
|
|
|
// Remove existing classes
|
|
this.keywordInput.classList.remove("valid", "warning", "invalid");
|
|
|
|
// Jika input kosong atau hanya spasi, show empty state
|
|
if (!value || value.length === 0) {
|
|
this.showEmptyState("Mulai Pencarian");
|
|
return;
|
|
}
|
|
|
|
// Jika kurang dari 3 karakter, show warning
|
|
if (value.length < 3) {
|
|
this.showEmptyState("Minimal 3 karakter untuk pencarian");
|
|
this.keywordInput.classList.add("warning");
|
|
return;
|
|
}
|
|
|
|
// Jika valid, add valid class
|
|
this.keywordInput.classList.add("valid");
|
|
});
|
|
|
|
// Handle input focus untuk clear warning state
|
|
this.keywordInput.addEventListener("focus", () => {
|
|
const value = this.keywordInput.value.trim();
|
|
if (value.length >= 3) {
|
|
// Jika sudah valid, hide empty state
|
|
this.emptyState.style.display = "none";
|
|
}
|
|
});
|
|
|
|
// Handle input blur untuk final validation
|
|
this.keywordInput.addEventListener("blur", () => {
|
|
const value = this.keywordInput.value.trim();
|
|
if (!value || value.length === 0) {
|
|
this.showEmptyState("Mulai Pencarian");
|
|
} else if (value.length < 3) {
|
|
this.showEmptyState("Minimal 3 karakter untuk pencarian");
|
|
}
|
|
});
|
|
|
|
// Handle Escape key untuk clear search
|
|
this.keywordInput.addEventListener("keydown", (event) => {
|
|
if (event.key === "Escape") {
|
|
this.clearSearch();
|
|
}
|
|
});
|
|
}
|
|
|
|
buildUrl(keyword) {
|
|
const url = new URL(this.baseUrl, window.location.origin);
|
|
|
|
// Validasi keyword tidak kosong dan tidak hanya spasi
|
|
if (keyword && keyword.trim() !== "" && keyword.trim().length >= 3) {
|
|
url.searchParams.set("search", keyword.trim());
|
|
} else {
|
|
url.searchParams.delete("search"); // pastikan tidak ada search param
|
|
}
|
|
|
|
return url.toString();
|
|
}
|
|
|
|
showSearchResults() {
|
|
this.searchHeader.style.display = "block";
|
|
this.tableWrapper.style.display = "block";
|
|
this.emptyState.style.display = "none";
|
|
}
|
|
|
|
showEmptyState(message = "Tidak ada data yang ditemukan") {
|
|
this.searchHeader.style.display = "none";
|
|
this.tableWrapper.style.display = "none";
|
|
this.emptyState.style.display = "block";
|
|
|
|
// Update empty state message and icon
|
|
const emptyStateTitle = this.emptyState.querySelector("h4");
|
|
const emptyStateDesc = this.emptyState.querySelector("p");
|
|
const emptyIcon = this.emptyState.querySelector(".empty-icon i");
|
|
|
|
if (emptyStateTitle) {
|
|
emptyStateTitle.textContent = message;
|
|
}
|
|
|
|
if (emptyStateDesc) {
|
|
if (message === "Mulai Pencarian") {
|
|
emptyStateDesc.textContent =
|
|
"Masukkan kata kunci minimal 3 karakter untuk mencari data PBG";
|
|
} else if (message === "Minimal 3 karakter untuk pencarian") {
|
|
emptyStateDesc.textContent =
|
|
"Masukkan kata kunci minimal 3 karakter untuk mencari data PBG";
|
|
} else {
|
|
emptyStateDesc.textContent =
|
|
"Coba gunakan kata kunci yang berbeda atau lebih spesifik";
|
|
}
|
|
}
|
|
|
|
// Update icon based on message
|
|
if (emptyIcon) {
|
|
if (message === "Mulai Pencarian") {
|
|
emptyIcon.className = "fas fa-search fa-3x text-muted";
|
|
} else if (message === "Minimal 3 karakter untuk pencarian") {
|
|
emptyIcon.className =
|
|
"fas fa-exclamation-triangle fa-3x text-warning";
|
|
} else {
|
|
emptyIcon.className = "fas fa-search fa-3x text-muted";
|
|
}
|
|
}
|
|
|
|
// Clear existing table if any
|
|
if (this.table) {
|
|
this.table.destroy();
|
|
this.table = null;
|
|
}
|
|
}
|
|
|
|
clearSearch() {
|
|
this.keywordInput.value = "";
|
|
this.showEmptyState("Mulai Pencarian");
|
|
|
|
// Reset CSS classes
|
|
this.keywordInput.classList.remove("valid", "warning", "invalid");
|
|
|
|
// Clear URL parameter
|
|
const newUrl = window.location.pathname;
|
|
window.history.pushState({ path: newUrl }, "", newUrl);
|
|
|
|
// Reset datatable URL
|
|
this.datatableUrl = null;
|
|
}
|
|
|
|
initDatatable() {
|
|
const tableContainer = document.getElementById(
|
|
"datatable-public-search"
|
|
);
|
|
|
|
const config = {
|
|
columns: [
|
|
{ name: "ID", width: "80px" },
|
|
{ name: "Nama Pemohon", width: "150px" },
|
|
{ name: "Nama Pemilik", width: "150px" },
|
|
{ name: "Kondisi", width: "120px" },
|
|
{ name: "Nomor Registrasi", width: "180px" },
|
|
{ name: "Status", width: "120px" },
|
|
{ name: "Jenis Fungsi", width: "150px" },
|
|
{ name: "Nama Bangunan", width: "200px" },
|
|
{ name: "Jenis Konsultasi", width: "150px" },
|
|
{ name: "Tanggal Jatuh Tempo", width: "140px" },
|
|
{ name: "Retribusi", width: "120px" },
|
|
{ name: "Catatan Kekurangan Dokumen", width: "120px" },
|
|
],
|
|
search: false,
|
|
pagination: {
|
|
limit: 15,
|
|
server: {
|
|
url: (prev, page) =>
|
|
`${prev}${prev.includes("?") ? "&" : "?"}page=${
|
|
page + 1
|
|
}`,
|
|
},
|
|
},
|
|
sort: true,
|
|
server: {
|
|
url: this.datatableUrl,
|
|
then: (data) => {
|
|
// Check if data is empty
|
|
if (!data.data || data.data.length === 0) {
|
|
this.showEmptyState(
|
|
data.message || "Tidak ada data yang ditemukan"
|
|
);
|
|
return [];
|
|
}
|
|
|
|
return data.data.map((item) => [
|
|
item.id || "-",
|
|
item.name || "-",
|
|
item.owner_name || "-",
|
|
item.condition || "-",
|
|
item.registration_number || "-",
|
|
item.status_name || "-",
|
|
item.function_type || "-",
|
|
item.name_building || "-",
|
|
item.consultation_type || "-",
|
|
item.due_date || "-",
|
|
item.nilai_retribusi_bangunan
|
|
? addThousandSeparators(
|
|
item.nilai_retribusi_bangunan
|
|
)
|
|
: "-",
|
|
item.note || "-",
|
|
]);
|
|
},
|
|
total: (data) => data.total || 0,
|
|
error: (error) => {
|
|
console.error("Datatable error:", error);
|
|
this.showEmptyState(
|
|
"Terjadi kesalahan saat mengambil data"
|
|
);
|
|
},
|
|
},
|
|
};
|
|
|
|
if (this.table) {
|
|
this.table
|
|
.updateConfig({
|
|
...config,
|
|
server: { ...config.server, url: this.datatableUrl },
|
|
})
|
|
.forceRender();
|
|
} else {
|
|
tableContainer.innerHTML = "";
|
|
this.table = new Grid(config).render(tableContainer);
|
|
}
|
|
}
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
const app = new PublicSearch();
|
|
app.init();
|
|
});
|