1008 lines
34 KiB
JavaScript
1008 lines
34 KiB
JavaScript
window.fetchJson = async function (url, fallbackValue) {
|
||
var response = await fetch(url, {
|
||
cache: "no-store"
|
||
});
|
||
var text = await response.text();
|
||
|
||
if (!response.ok) {
|
||
if (fallbackValue !== undefined) {
|
||
console.error("Gagal memuat " + url + ": HTTP " + response.status);
|
||
return fallbackValue;
|
||
}
|
||
|
||
throw new Error("HTTP " + response.status + " saat memuat " + url);
|
||
}
|
||
|
||
if (!text.trim()) {
|
||
if (fallbackValue !== undefined) {
|
||
console.error("Respons kosong saat memuat " + url);
|
||
return fallbackValue;
|
||
}
|
||
|
||
throw new Error("Respons kosong saat memuat " + url);
|
||
}
|
||
|
||
try {
|
||
return JSON.parse(text);
|
||
} catch (error) {
|
||
if (fallbackValue !== undefined) {
|
||
console.error("Gagal parse JSON dari " + url + ":", error, text);
|
||
return fallbackValue;
|
||
}
|
||
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
window.isValidCoordinate = function (latitude, longitude) {
|
||
return Number.isFinite(Number(latitude)) && Number.isFinite(Number(longitude));
|
||
};
|
||
|
||
window.isValidRadius = function (radius) {
|
||
return Number.isFinite(Number(radius)) && Number(radius) >= 100 && Number(radius) <= 5000;
|
||
};
|
||
|
||
window.deleteRecord = async function (url, id, label) {
|
||
if (window.appState.mode !== "edit") {
|
||
alert("Pindah ke mode edit untuk menghapus data.");
|
||
return;
|
||
}
|
||
|
||
var confirmed = window.confirm("Hapus data " + label + " ini?");
|
||
if (!confirmed) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await window.postForm(url, { id: id });
|
||
await window.loadAllData();
|
||
alert("Data berhasil dihapus.");
|
||
} catch (error) {
|
||
alert("Gagal menghapus data: " + error.message);
|
||
}
|
||
};
|
||
|
||
window.updateMasjidRadius = async function (masjid) {
|
||
if (window.appState.mode !== "edit") {
|
||
alert("Pindah ke mode edit untuk mengubah radius masjid.");
|
||
return;
|
||
}
|
||
|
||
var radiusInput = window.prompt("Masukkan radius masjid (100 - 5000 meter):", String(Math.round(masjid.radius)));
|
||
if (radiusInput === null) {
|
||
return;
|
||
}
|
||
|
||
var radius = parseInt(radiusInput.trim(), 10);
|
||
if (!Number.isInteger(radius) || radius < 100 || radius > 5000) {
|
||
alert("Radius harus berupa angka antara 100 sampai 5000 meter.");
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await window.postForm("php/update_masjid_radius.php", {
|
||
id: masjid.id,
|
||
radius: radius
|
||
});
|
||
await window.loadAllData();
|
||
alert("Radius masjid berhasil diperbarui.");
|
||
} catch (error) {
|
||
alert("Gagal memperbarui radius masjid: " + error.message);
|
||
}
|
||
};
|
||
|
||
window.openEditModal = function (config) {
|
||
return new Promise(function (resolve) {
|
||
var backdrop = document.getElementById("editModalBackdrop");
|
||
var form = document.getElementById("editModalForm");
|
||
var title = document.getElementById("editModalTitle");
|
||
var subtitle = document.getElementById("editModalSubtitle");
|
||
var fieldsWrap = document.getElementById("editModalFields");
|
||
var errorBox = document.getElementById("editModalError");
|
||
var closeButton = document.getElementById("editModalClose");
|
||
var cancelButton = document.getElementById("editModalCancel");
|
||
|
||
if (!backdrop || !form || !title || !subtitle || !fieldsWrap || !errorBox || !closeButton || !cancelButton) {
|
||
resolve(null);
|
||
return;
|
||
}
|
||
|
||
var isResolved = false;
|
||
|
||
var cleanup = function (value) {
|
||
if (isResolved) {
|
||
return;
|
||
}
|
||
|
||
isResolved = true;
|
||
form.onsubmit = null;
|
||
closeButton.onclick = null;
|
||
cancelButton.onclick = null;
|
||
backdrop.onclick = null;
|
||
document.removeEventListener("keydown", onKeydown);
|
||
backdrop.classList.remove("is-open");
|
||
backdrop.setAttribute("aria-hidden", "true");
|
||
resolve(value);
|
||
};
|
||
|
||
var onKeydown = function (event) {
|
||
if (event.key === "Escape") {
|
||
cleanup(null);
|
||
}
|
||
};
|
||
|
||
title.textContent = config.title;
|
||
subtitle.textContent = config.subtitle || "Perbarui atribut data terpilih.";
|
||
fieldsWrap.innerHTML = "";
|
||
errorBox.textContent = "";
|
||
errorBox.classList.remove("is-visible");
|
||
|
||
config.fields.forEach(function (field) {
|
||
var fieldWrap = document.createElement("div");
|
||
fieldWrap.className = "form-field";
|
||
|
||
var label = document.createElement("label");
|
||
label.setAttribute("for", "edit-field-" + field.name);
|
||
label.textContent = field.label;
|
||
fieldWrap.appendChild(label);
|
||
|
||
var input;
|
||
if (field.type === "select") {
|
||
input = document.createElement("select");
|
||
field.options.forEach(function (optionConfig) {
|
||
var option = document.createElement("option");
|
||
option.value = optionConfig.value;
|
||
option.textContent = optionConfig.label;
|
||
input.appendChild(option);
|
||
});
|
||
} else if (field.type === "textarea") {
|
||
input = document.createElement("textarea");
|
||
} else {
|
||
input = document.createElement("input");
|
||
input.type = field.type || "text";
|
||
}
|
||
|
||
input.id = "edit-field-" + field.name;
|
||
input.name = field.name;
|
||
input.value = field.value ?? "";
|
||
if (field.required) {
|
||
input.required = true;
|
||
}
|
||
if (field.min !== undefined) {
|
||
input.min = field.min;
|
||
}
|
||
if (field.max !== undefined) {
|
||
input.max = field.max;
|
||
}
|
||
if (field.step !== undefined) {
|
||
input.step = field.step;
|
||
}
|
||
|
||
fieldWrap.appendChild(input);
|
||
fieldsWrap.appendChild(fieldWrap);
|
||
});
|
||
|
||
var showError = function (message) {
|
||
errorBox.textContent = message;
|
||
errorBox.classList.add("is-visible");
|
||
};
|
||
|
||
form.onsubmit = function (event) {
|
||
event.preventDefault();
|
||
|
||
var values = {};
|
||
config.fields.forEach(function (field) {
|
||
var input = form.elements[field.name];
|
||
values[field.name] = field.type === "number"
|
||
? Number(input.value)
|
||
: String(input.value).trim();
|
||
});
|
||
|
||
var validationError = typeof config.validate === "function" ? config.validate(values) : "";
|
||
if (validationError) {
|
||
showError(validationError);
|
||
return;
|
||
}
|
||
|
||
cleanup(values);
|
||
};
|
||
|
||
closeButton.onclick = function () {
|
||
cleanup(null);
|
||
};
|
||
cancelButton.onclick = function () {
|
||
cleanup(null);
|
||
};
|
||
backdrop.onclick = function (event) {
|
||
if (event.target === backdrop) {
|
||
cleanup(null);
|
||
}
|
||
};
|
||
document.addEventListener("keydown", onKeydown);
|
||
|
||
backdrop.classList.add("is-open");
|
||
backdrop.setAttribute("aria-hidden", "false");
|
||
|
||
var firstInput = fieldsWrap.querySelector("input, select, textarea");
|
||
if (firstInput) {
|
||
firstInput.focus();
|
||
if (typeof firstInput.select === "function" && firstInput.tagName !== "SELECT") {
|
||
firstInput.select();
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
window.editSpbu = async function (spbu) {
|
||
if (window.appState.mode !== "edit") {
|
||
alert("Pindah ke mode edit untuk mengubah data.");
|
||
return;
|
||
}
|
||
|
||
var values = await window.openEditModal({
|
||
title: "Edit SPBU",
|
||
subtitle: "Ubah nama, nomor, dan status operasional SPBU.",
|
||
fields: [
|
||
{ name: "nama", label: "Nama SPBU", value: spbu.nama, required: true },
|
||
{ name: "no", label: "Nomor SPBU", value: spbu.no_spbu, required: true },
|
||
{
|
||
name: "status",
|
||
label: "Status Operasional",
|
||
type: "select",
|
||
value: spbu.status,
|
||
options: [
|
||
{ value: "24jam", label: "24 Jam" },
|
||
{ value: "tidak", label: "Tidak 24 Jam" }
|
||
]
|
||
}
|
||
],
|
||
validate: function (data) {
|
||
if (!data.nama || !data.no) {
|
||
return "Nama dan nomor SPBU wajib diisi.";
|
||
}
|
||
return "";
|
||
}
|
||
});
|
||
|
||
if (!values) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await window.postForm("php/update.php", {
|
||
id: spbu.id,
|
||
nama: values.nama,
|
||
no: values.no,
|
||
status: values.status
|
||
});
|
||
await window.loadAllData();
|
||
alert("Data SPBU berhasil diperbarui.");
|
||
} catch (error) {
|
||
alert("Gagal memperbarui SPBU: " + error.message);
|
||
}
|
||
};
|
||
|
||
window.editKemiskinan = async function (kemiskinan) {
|
||
if (window.appState.mode !== "edit") {
|
||
alert("Pindah ke mode edit untuk mengubah data.");
|
||
return;
|
||
}
|
||
|
||
var values = await window.openEditModal({
|
||
title: "Edit Data Kemiskinan",
|
||
subtitle: "Ubah kepala keluarga, jumlah KK, dan alamat.",
|
||
fields: [
|
||
{ name: "nama_kepala_keluarga", label: "Nama Kepala Keluarga", value: kemiskinan.nama_kepala_keluarga, required: true },
|
||
{ name: "jumlah_kk", label: "Jumlah KK", type: "number", min: 1, step: 1, value: kemiskinan.jumlah_kk, required: true },
|
||
{ name: "alamat", label: "Alamat", type: "textarea", value: kemiskinan.alamat, required: true }
|
||
],
|
||
validate: function (data) {
|
||
if (!data.nama_kepala_keluarga || !data.alamat) {
|
||
return "Nama kepala keluarga dan alamat wajib diisi.";
|
||
}
|
||
if (!Number.isInteger(data.jumlah_kk) || data.jumlah_kk < 1) {
|
||
return "Jumlah KK harus angka minimal 1.";
|
||
}
|
||
return "";
|
||
}
|
||
});
|
||
|
||
if (!values) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await window.postForm("php/update_kemiskinan.php", {
|
||
id: kemiskinan.id,
|
||
nama_kepala_keluarga: values.nama_kepala_keluarga,
|
||
jumlah_kk: values.jumlah_kk,
|
||
alamat: values.alamat
|
||
});
|
||
await window.loadAllData();
|
||
alert("Data kemiskinan berhasil diperbarui.");
|
||
} catch (error) {
|
||
alert("Gagal memperbarui data kemiskinan: " + error.message);
|
||
}
|
||
};
|
||
|
||
window.editMasjid = async function (masjid) {
|
||
if (window.appState.mode !== "edit") {
|
||
alert("Pindah ke mode edit untuk mengubah data.");
|
||
return;
|
||
}
|
||
|
||
var values = await window.openEditModal({
|
||
title: "Edit Masjid",
|
||
subtitle: "Ubah identitas masjid, alamat, dan radius jangkauan.",
|
||
fields: [
|
||
{ name: "nama_masjid", label: "Nama Masjid", value: masjid.nama_masjid, required: true },
|
||
{ name: "pic_masjid", label: "PIC Masjid", value: masjid.pic_masjid, required: true },
|
||
{ name: "alamat", label: "Alamat Masjid", type: "textarea", value: masjid.alamat, required: true },
|
||
{ name: "radius", label: "Radius Jangkauan (meter)", type: "number", min: 100, max: 5000, step: 1, value: Math.round(masjid.radius), required: true }
|
||
],
|
||
validate: function (data) {
|
||
if (!data.nama_masjid || !data.pic_masjid || !data.alamat) {
|
||
return "Nama, PIC, dan alamat masjid wajib diisi.";
|
||
}
|
||
if (!Number.isInteger(data.radius) || data.radius < 100 || data.radius > 5000) {
|
||
return "Radius harus angka antara 100 sampai 5000 meter.";
|
||
}
|
||
return "";
|
||
}
|
||
});
|
||
|
||
if (!values) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await window.postForm("php/update_masjid.php", {
|
||
id: masjid.id,
|
||
nama_masjid: values.nama_masjid,
|
||
pic_masjid: values.pic_masjid,
|
||
alamat: values.alamat,
|
||
radius: values.radius
|
||
});
|
||
await window.loadAllData();
|
||
alert("Data masjid berhasil diperbarui.");
|
||
} catch (error) {
|
||
alert("Gagal memperbarui data masjid: " + error.message);
|
||
}
|
||
};
|
||
|
||
window.editRoad = async function (jalan) {
|
||
if (window.appState.mode !== "edit") {
|
||
alert("Pindah ke mode edit untuk mengubah data.");
|
||
return;
|
||
}
|
||
|
||
var values = await window.openEditModal({
|
||
title: "Edit Jalan",
|
||
subtitle: "Ubah nama dan status jalan. Bentuk garis tetap mengikuti geometri yang sudah digambar.",
|
||
fields: [
|
||
{ name: "nama", label: "Nama Jalan", value: jalan.nama, required: true },
|
||
{
|
||
name: "status",
|
||
label: "Status Jalan",
|
||
type: "select",
|
||
value: jalan.status,
|
||
options: [
|
||
{ value: "Jalan Nasional", label: "Jalan Nasional" },
|
||
{ value: "Jalan Provinsi", label: "Jalan Provinsi" },
|
||
{ value: "Jalan Kabupaten", label: "Jalan Kabupaten" }
|
||
]
|
||
}
|
||
],
|
||
validate: function (data) {
|
||
if (!data.nama || !window.normalizeRoadStatus(data.status)) {
|
||
return "Nama dan status jalan wajib valid.";
|
||
}
|
||
return "";
|
||
}
|
||
});
|
||
|
||
if (!values) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await window.postForm("php/update_line.php", {
|
||
id: jalan.id,
|
||
nama: values.nama,
|
||
status: values.status
|
||
});
|
||
await window.loadAllData();
|
||
alert("Data jalan berhasil diperbarui.");
|
||
} catch (error) {
|
||
alert("Gagal memperbarui jalan: " + error.message);
|
||
}
|
||
};
|
||
|
||
window.editPolygon = async function (kavling) {
|
||
if (window.appState.mode !== "edit") {
|
||
alert("Pindah ke mode edit untuk mengubah data.");
|
||
return;
|
||
}
|
||
|
||
var values = await window.openEditModal({
|
||
title: "Edit Kavling",
|
||
subtitle: "Ubah nama dan status kavling. Bentuk polygon tetap mengikuti geometri yang sudah digambar.",
|
||
fields: [
|
||
{ name: "nama", label: "Nama Kavling", value: kavling.nama, required: true },
|
||
{
|
||
name: "status",
|
||
label: "Status Kavling",
|
||
type: "select",
|
||
value: kavling.status,
|
||
options: [
|
||
{ value: "SHM", label: "SHM" },
|
||
{ value: "HGB", label: "HGB" },
|
||
{ value: "HGU", label: "HGU" },
|
||
{ value: "HP", label: "HP" }
|
||
]
|
||
}
|
||
],
|
||
validate: function (data) {
|
||
if (!data.nama || !window.normalizePolygonStatus(data.status)) {
|
||
return "Nama dan status kavling wajib valid.";
|
||
}
|
||
return "";
|
||
}
|
||
});
|
||
|
||
if (!values) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await window.postForm("php/update_polygon.php", {
|
||
id: kavling.id,
|
||
nama: values.nama,
|
||
status: values.status
|
||
});
|
||
await window.loadAllData();
|
||
alert("Data kavling berhasil diperbarui.");
|
||
} catch (error) {
|
||
alert("Gagal memperbarui kavling: " + error.message);
|
||
}
|
||
};
|
||
|
||
window.createSidebarActionButton = function (config) {
|
||
var button = document.createElement("button");
|
||
button.className = config.className;
|
||
button.type = "button";
|
||
button.textContent = config.label;
|
||
button.disabled = !!config.disabled;
|
||
button.onclick = function (event) {
|
||
event.stopPropagation();
|
||
config.onClick();
|
||
};
|
||
return button;
|
||
};
|
||
|
||
window.createSidebarCardElement = function (config) {
|
||
var card = document.createElement("div");
|
||
card.className = "card";
|
||
card.onclick = function () {
|
||
if (window.appState.mode === "edit" && typeof config.onEdit === "function") {
|
||
config.onEdit();
|
||
return;
|
||
}
|
||
|
||
config.onFocus();
|
||
};
|
||
|
||
var title = document.createElement("div");
|
||
title.className = "title";
|
||
title.textContent = config.title;
|
||
card.appendChild(title);
|
||
|
||
var body = document.createElement("div");
|
||
body.className = "card-body";
|
||
body.textContent = config.body;
|
||
card.appendChild(body);
|
||
|
||
var meta = document.createElement("div");
|
||
meta.className = "meta";
|
||
meta.textContent = config.meta;
|
||
card.appendChild(meta);
|
||
|
||
var actions = document.createElement("div");
|
||
actions.className = "card-actions";
|
||
|
||
var badgeWrap = document.createElement("div");
|
||
badgeWrap.className = "meta";
|
||
var badge = document.createElement("span");
|
||
badge.className = "badge " + config.badgeClass;
|
||
badge.textContent = config.badgeText;
|
||
badgeWrap.appendChild(badge);
|
||
actions.appendChild(badgeWrap);
|
||
|
||
var actionButtons = document.createElement("div");
|
||
actionButtons.style.display = "flex";
|
||
actionButtons.style.gap = "6px";
|
||
|
||
if (Array.isArray(config.buttons)) {
|
||
config.buttons.forEach(function (buttonConfig) {
|
||
actionButtons.appendChild(window.createSidebarActionButton(buttonConfig));
|
||
});
|
||
}
|
||
|
||
actions.appendChild(actionButtons);
|
||
card.appendChild(actions);
|
||
return card;
|
||
};
|
||
|
||
window.createSectionElement = function (title, items) {
|
||
var section = document.createElement("div");
|
||
section.className = "section";
|
||
|
||
var heading = document.createElement("h3");
|
||
var headingText = document.createElement("span");
|
||
headingText.textContent = title;
|
||
heading.appendChild(headingText);
|
||
|
||
var count = document.createElement("span");
|
||
count.className = "section-count";
|
||
count.textContent = items.length;
|
||
heading.appendChild(count);
|
||
section.appendChild(heading);
|
||
|
||
if (!items.length) {
|
||
var emptyState = document.createElement("div");
|
||
emptyState.className = "empty-state";
|
||
emptyState.textContent = "Belum ada data.";
|
||
section.appendChild(emptyState);
|
||
return section;
|
||
}
|
||
|
||
items.forEach(function (item) {
|
||
section.appendChild(item);
|
||
});
|
||
|
||
return section;
|
||
};
|
||
|
||
window.getLayerFilterDefinitions = function () {
|
||
return [
|
||
{ key: "spbu24", label: "SPBU 24 Jam" },
|
||
{ key: "spbuTidak", label: "SPBU Tidak 24 Jam" },
|
||
{ key: "kemiskinan", label: "Kemiskinan" },
|
||
{ key: "masjid", label: "Masjid" },
|
||
{ key: "jalan", label: "Jalan" },
|
||
{ key: "kavling", label: "Kavling" }
|
||
];
|
||
};
|
||
|
||
window.createLayerFilterSection = function () {
|
||
var section = document.createElement("div");
|
||
section.className = "panel-section";
|
||
|
||
var heading = document.createElement("h3");
|
||
heading.textContent = "Filter Layer Peta";
|
||
section.appendChild(heading);
|
||
|
||
var filterBox = document.createElement("div");
|
||
filterBox.className = "filter-box";
|
||
|
||
window.getLayerFilterDefinitions().forEach(function (filter) {
|
||
var row = document.createElement("label");
|
||
row.className = "filter-item";
|
||
|
||
var checkbox = document.createElement("input");
|
||
checkbox.type = "checkbox";
|
||
checkbox.dataset.layerKey = filter.key;
|
||
checkbox.checked = !!appState.layerVisibility[filter.key];
|
||
checkbox.onchange = function () {
|
||
window.setLayerVisibility(filter.key, checkbox.checked);
|
||
};
|
||
|
||
var text = document.createElement("span");
|
||
text.textContent = filter.label;
|
||
|
||
row.appendChild(checkbox);
|
||
row.appendChild(text);
|
||
filterBox.appendChild(row);
|
||
});
|
||
|
||
section.appendChild(filterBox);
|
||
return section;
|
||
};
|
||
|
||
window.refreshLayerFilterUI = function () {
|
||
var checkboxes = document.querySelectorAll("input[data-layer-key]");
|
||
checkboxes.forEach(function (checkbox) {
|
||
var key = checkbox.dataset.layerKey;
|
||
checkbox.checked = !!appState.layerVisibility[key];
|
||
});
|
||
};
|
||
|
||
window.updateDashboardStats = function (spbus, masjid, roads, lands) {
|
||
var statSpbu = document.getElementById("statSpbu");
|
||
var statMasjid = document.getElementById("statMasjid");
|
||
var statJalan = document.getElementById("statJalan");
|
||
var statKavling = document.getElementById("statKavling");
|
||
|
||
if (statSpbu) {
|
||
statSpbu.textContent = spbus.length;
|
||
}
|
||
|
||
if (statMasjid) {
|
||
statMasjid.textContent = masjid.length;
|
||
}
|
||
|
||
if (statJalan) {
|
||
statJalan.textContent = roads.length;
|
||
}
|
||
|
||
if (statKavling) {
|
||
statKavling.textContent = lands.length;
|
||
}
|
||
};
|
||
|
||
window.renderDataPanelHeader = function (sidebar) {
|
||
var header = document.createElement("div");
|
||
header.className = "sidebar-header";
|
||
|
||
var headerText = document.createElement("div");
|
||
|
||
var title = document.createElement("h2");
|
||
title.className = "sidebar-title";
|
||
title.textContent = "▰ Manajemen Data";
|
||
headerText.appendChild(title);
|
||
|
||
var subtitle = document.createElement("p");
|
||
subtitle.className = "sidebar-subtitle";
|
||
subtitle.textContent = appState.mode === "edit"
|
||
? "Mode edit aktif. Klik kartu untuk mengubah data, gunakan Hapus untuk menghapus."
|
||
: "Mode lihat aktif. Klik kartu untuk fokus ke objek di peta.";
|
||
headerText.appendChild(subtitle);
|
||
|
||
var closeButton = document.createElement("button");
|
||
closeButton.className = "panel-close";
|
||
closeButton.type = "button";
|
||
closeButton.textContent = "×";
|
||
|
||
header.appendChild(headerText);
|
||
header.appendChild(closeButton);
|
||
sidebar.appendChild(header);
|
||
|
||
};
|
||
|
||
window.renderLayerFilters = function () {
|
||
var target = document.getElementById("layerFilters");
|
||
if (!target) {
|
||
return;
|
||
}
|
||
|
||
target.innerHTML = "";
|
||
target.appendChild(window.createLayerFilterSection());
|
||
};
|
||
|
||
window.loadAllData = async function () {
|
||
var sidebar = document.getElementById("sidebar");
|
||
if (!sidebar || !window.map || !window.appState.layers.spbu24 || !window.appState.layers.spbuTidak || !window.appState.layers.kemiskinan || !window.appState.layers.masjid) {
|
||
return;
|
||
}
|
||
|
||
sidebar.innerHTML =
|
||
'<div class="sidebar-header"><div><h2 class="sidebar-title">▰ Manajemen Data</h2>' +
|
||
'<p class="sidebar-subtitle">Memuat data dari database...</p></div></div>';
|
||
|
||
appState.layers.spbu24.clearLayers();
|
||
appState.layers.spbuTidak.clearLayers();
|
||
appState.layers.kemiskinan.clearLayers();
|
||
appState.layers.masjid.clearLayers();
|
||
appState.layers.jalan.clearLayers();
|
||
appState.layers.kavling.clearLayers();
|
||
|
||
try {
|
||
var results = await Promise.all([
|
||
window.fetchJson("php/read.php", []),
|
||
window.fetchJson("php/read_kemiskinan.php", []),
|
||
window.fetchJson("php/read_masjid.php", []),
|
||
window.fetchJson("php/read_line.php", []),
|
||
window.fetchJson("php/read_polygon.php", [])
|
||
]);
|
||
var spbus = results[0];
|
||
var dataKemiskinan = results[1];
|
||
var masjid = results[2];
|
||
var roads = results[3];
|
||
var lands = results[4];
|
||
|
||
sidebar.innerHTML = "";
|
||
window.renderDataPanelHeader(sidebar);
|
||
window.renderLayerFilters();
|
||
window.updateDashboardStats(spbus, masjid, roads, lands);
|
||
|
||
sidebar.appendChild(window.renderSpbu(spbus));
|
||
sidebar.appendChild(window.renderKemiskinan(dataKemiskinan));
|
||
sidebar.appendChild(window.renderMasjid(masjid));
|
||
sidebar.appendChild(window.renderRoads(roads));
|
||
sidebar.appendChild(window.renderPolygons(lands));
|
||
} catch (error) {
|
||
sidebar.innerHTML =
|
||
'<div class="sidebar-header"><div><h2 class="sidebar-title">▰ Manajemen Data</h2>' +
|
||
'<p class="sidebar-subtitle">Terjadi kendala saat membaca data.</p></div></div>' +
|
||
'<div class="empty-state">' + window.escapeHtml(error.message) + "</div>";
|
||
console.error(error);
|
||
}
|
||
};
|
||
|
||
window.renderSpbu = function (spbus) {
|
||
var items = [];
|
||
|
||
spbus.forEach(function (spbu) {
|
||
if (!window.isValidCoordinate(spbu.latitude, spbu.longitude)) {
|
||
return;
|
||
}
|
||
|
||
var targetGroup = spbu.status === "24jam" ? appState.layers.spbu24 : appState.layers.spbuTidak;
|
||
var marker = L.marker([spbu.latitude, spbu.longitude], {
|
||
icon: spbu.status === "24jam" ? greenIcon : redIcon
|
||
}).addTo(targetGroup).bindPopup(
|
||
"<b>" + window.escapeHtml(spbu.nama) + "</b><br>" +
|
||
"No: " + window.escapeHtml(spbu.no_spbu) + "<br>" +
|
||
"Status: " + (spbu.status === "24jam" ? "24 Jam" : "Tidak")
|
||
);
|
||
|
||
items.push(
|
||
window.createSidebarCardElement({
|
||
title: spbu.nama,
|
||
body: "No: " + spbu.no_spbu,
|
||
meta: "Koordinat: " + Number(spbu.latitude).toFixed(6) + ", " + Number(spbu.longitude).toFixed(6),
|
||
badgeClass: spbu.status === "24jam" ? "green" : "red",
|
||
badgeText: spbu.status === "24jam" ? "24 Jam" : "Tidak",
|
||
onFocus: function () {
|
||
map.setView([spbu.latitude, spbu.longitude], 16);
|
||
marker.openPopup();
|
||
},
|
||
onEdit: function () {
|
||
window.editSpbu(spbu);
|
||
},
|
||
buttons: [
|
||
{
|
||
label: "Edit",
|
||
className: "secondary-btn",
|
||
disabled: window.appState.mode !== "edit",
|
||
onClick: function () {
|
||
window.editSpbu(spbu);
|
||
}
|
||
},
|
||
{
|
||
label: "Hapus",
|
||
className: "delete-btn",
|
||
disabled: window.appState.mode !== "edit",
|
||
onClick: function () {
|
||
window.deleteRecord("php/delete.php", spbu.id, "SPBU");
|
||
}
|
||
}
|
||
]
|
||
})
|
||
);
|
||
});
|
||
|
||
return window.createSectionElement("SPBU", items);
|
||
};
|
||
|
||
window.renderKemiskinan = function (dataKemiskinan) {
|
||
var items = [];
|
||
|
||
dataKemiskinan.forEach(function (kemiskinan) {
|
||
if (!window.isValidCoordinate(kemiskinan.latitude, kemiskinan.longitude)) {
|
||
return;
|
||
}
|
||
|
||
var marker = L.marker([kemiskinan.latitude, kemiskinan.longitude], {
|
||
icon: orangeIcon
|
||
}).addTo(appState.layers.kemiskinan).bindPopup(
|
||
"<b>" + window.escapeHtml(kemiskinan.nama_kepala_keluarga) + "</b><br>" +
|
||
"Jumlah KK: " + window.escapeHtml(kemiskinan.jumlah_kk) + "<br>" +
|
||
"Alamat: " + window.escapeHtml(kemiskinan.alamat)
|
||
);
|
||
|
||
items.push(
|
||
window.createSidebarCardElement({
|
||
title: kemiskinan.nama_kepala_keluarga,
|
||
body: "Jumlah KK: " + kemiskinan.jumlah_kk,
|
||
meta: kemiskinan.alamat,
|
||
badgeClass: "orange",
|
||
badgeText: "Kemiskinan",
|
||
onFocus: function () {
|
||
map.setView([kemiskinan.latitude, kemiskinan.longitude], 16);
|
||
marker.openPopup();
|
||
},
|
||
onEdit: function () {
|
||
window.editKemiskinan(kemiskinan);
|
||
},
|
||
buttons: [
|
||
{
|
||
label: "Edit",
|
||
className: "secondary-btn",
|
||
disabled: window.appState.mode !== "edit",
|
||
onClick: function () {
|
||
window.editKemiskinan(kemiskinan);
|
||
}
|
||
},
|
||
{
|
||
label: "Hapus",
|
||
className: "delete-btn",
|
||
disabled: window.appState.mode !== "edit",
|
||
onClick: function () {
|
||
window.deleteRecord("php/delete_kemiskinan.php", kemiskinan.id, "Kemiskinan");
|
||
}
|
||
}
|
||
]
|
||
})
|
||
);
|
||
});
|
||
|
||
return window.createSectionElement("Kemiskinan", items);
|
||
};
|
||
|
||
window.renderMasjid = function (masjidList) {
|
||
var items = [];
|
||
|
||
masjidList.forEach(function (masjid) {
|
||
var radius = Number(masjid.radius);
|
||
if (!window.isValidCoordinate(masjid.latitude, masjid.longitude) || !window.isValidRadius(radius)) {
|
||
return;
|
||
}
|
||
|
||
var popupContent =
|
||
"<b>" + window.escapeHtml(masjid.nama_masjid) + "</b><br>" +
|
||
"PIC: " + window.escapeHtml(masjid.pic_masjid) + "<br>" +
|
||
"Alamat: " + window.escapeHtml(masjid.alamat) + "<br>" +
|
||
"Radius: " + window.formatMeters(radius);
|
||
|
||
var circle = L.circle([masjid.latitude, masjid.longitude], {
|
||
radius: radius,
|
||
color: "#007bff",
|
||
fillColor: "#60a5fa",
|
||
fillOpacity: 0.15,
|
||
weight: 2
|
||
}).addTo(appState.layers.masjid).bindPopup(popupContent);
|
||
|
||
var marker = L.marker([masjid.latitude, masjid.longitude], {
|
||
icon: blueIcon
|
||
}).addTo(appState.layers.masjid).bindPopup(popupContent);
|
||
|
||
items.push(
|
||
window.createSidebarCardElement({
|
||
title: masjid.nama_masjid,
|
||
body: "PIC: " + masjid.pic_masjid,
|
||
meta: masjid.alamat + " | Radius: " + window.formatMeters(radius),
|
||
badgeClass: "blue",
|
||
badgeText: "Masjid",
|
||
onFocus: function () {
|
||
map.fitBounds(circle.getBounds(), { padding: [40, 40] });
|
||
marker.openPopup();
|
||
},
|
||
onEdit: function () {
|
||
window.editMasjid(masjid);
|
||
},
|
||
buttons: [
|
||
{
|
||
label: "Edit",
|
||
className: "secondary-btn",
|
||
disabled: window.appState.mode !== "edit",
|
||
onClick: function () {
|
||
window.editMasjid(masjid);
|
||
}
|
||
},
|
||
{
|
||
label: "Hapus",
|
||
className: "delete-btn",
|
||
disabled: window.appState.mode !== "edit",
|
||
onClick: function () {
|
||
window.deleteRecord("php/delete_masjid.php", masjid.id, "Masjid");
|
||
}
|
||
}
|
||
]
|
||
})
|
||
);
|
||
});
|
||
|
||
return window.createSectionElement("Masjid", items);
|
||
};
|
||
|
||
window.renderRoads = function (roads) {
|
||
var items = [];
|
||
|
||
roads.forEach(function (jalan) {
|
||
var layer = window.buildRoadLayer(jalan);
|
||
if (!layer) {
|
||
return;
|
||
}
|
||
|
||
layer.addTo(appState.layers.jalan);
|
||
|
||
items.push(
|
||
window.createSidebarCardElement({
|
||
title: jalan.nama,
|
||
body: "Status: " + jalan.status,
|
||
meta: "Panjang: " + window.formatMeters(jalan.panjang),
|
||
badgeClass: jalan.status === "Jalan Nasional" ? "red" : (jalan.status === "Jalan Provinsi" ? "blue" : "green"),
|
||
badgeText: "Jalan",
|
||
onFocus: function () {
|
||
map.fitBounds(layer.getBounds(), { padding: [30, 30] });
|
||
layer.openPopup();
|
||
},
|
||
onEdit: function () {
|
||
window.editRoad(jalan);
|
||
},
|
||
buttons: [
|
||
{
|
||
label: "Edit",
|
||
className: "secondary-btn",
|
||
disabled: window.appState.mode !== "edit",
|
||
onClick: function () {
|
||
window.editRoad(jalan);
|
||
}
|
||
},
|
||
{
|
||
label: "Hapus",
|
||
className: "delete-btn",
|
||
disabled: window.appState.mode !== "edit",
|
||
onClick: function () {
|
||
window.deleteRecord("php/delete_line.php", jalan.id, "Jalan");
|
||
}
|
||
}
|
||
]
|
||
})
|
||
);
|
||
});
|
||
|
||
return window.createSectionElement("Jalan", items);
|
||
};
|
||
|
||
window.renderPolygons = function (lands) {
|
||
var items = [];
|
||
|
||
lands.forEach(function (kavling) {
|
||
var layer = window.buildPolygonLayer(kavling);
|
||
if (!layer) {
|
||
return;
|
||
}
|
||
|
||
layer.addTo(appState.layers.kavling);
|
||
|
||
items.push(
|
||
window.createSidebarCardElement({
|
||
title: kavling.nama,
|
||
body: "Status: " + kavling.status,
|
||
meta: "Luas: " + window.formatSquareMeters(kavling.luas),
|
||
badgeClass: kavling.status === "SHM" ? "orange" : (kavling.status === "HP" ? "gray" : "blue"),
|
||
badgeText: "Kavling",
|
||
onFocus: function () {
|
||
map.fitBounds(layer.getBounds(), { padding: [30, 30] });
|
||
layer.openPopup();
|
||
},
|
||
onEdit: function () {
|
||
window.editPolygon(kavling);
|
||
},
|
||
buttons: [
|
||
{
|
||
label: "Edit",
|
||
className: "secondary-btn",
|
||
disabled: window.appState.mode !== "edit",
|
||
onClick: function () {
|
||
window.editPolygon(kavling);
|
||
}
|
||
},
|
||
{
|
||
label: "Hapus",
|
||
className: "delete-btn",
|
||
disabled: window.appState.mode !== "edit",
|
||
onClick: function () {
|
||
window.deleteRecord("php/delete_polygon.php", kavling.id, "Kavling");
|
||
}
|
||
}
|
||
]
|
||
})
|
||
);
|
||
});
|
||
|
||
return window.createSectionElement("Kavling", items);
|
||
};
|