// modules/point.js — Logika Pertemuan 1: Point of Interest (POI)
// Dipanggil oleh index.php saat mode = 1
(function () {
// ── Layer group ──────────────────────────────────
const layerGroup = L.layerGroup();
let allMarkers = {}; // { id: markerObject }
let tempMarker = null;
let active = false;
// ── Custom Icons ─────────────────────────────────
function createIcon(color = '#2ea043') {
return L.divIcon({
className: '',
html: ``,
iconSize: [28, 38],
iconAnchor: [14, 38],
popupAnchor: [0, -40]
});
}
const iconDefault = createIcon('#2ea043');
const iconClosed = createIcon('#f85149');
const iconTemp = createIcon('#e3b341');
// ── Render marker on map ─────────────────────────
function addMarkerToMap(poi) {
const isOpen = Number(poi.buka_24jam) === 1;
const marker = L.marker(
[poi.latitude, poi.longitude],
{ icon: isOpen ? iconDefault : iconClosed, draggable: true, pane: 'pointPane' }
);
marker._poiId = poi.id;
marker._poiNama = poi.nama_tempat;
marker._poiBuka = Number(poi.buka_24jam) === 1;
allMarkers[poi.id] = marker;
// Drag to update position
marker.on('dragend', function (e) {
const { lat, lng } = e.target.getLatLng();
const fd = new FormData();
fd.append('id', poi.id);
fd.append('latitude', lat.toFixed(8));
fd.append('longitude', lng.toFixed(8));
fetch('api/point/update_posisi.php', { method: 'POST', body: fd })
.then(r => r.json())
.then(j => {
if (j.status === 'success') showToast(`Posisi "${escapeHTML(poi.nama_tempat)}" diperbarui!`);
else throw new Error(j.message);
})
.catch(err => showToast(err.message || 'Gagal update posisi.', 'error'));
});
// Popup info
const noWa = poi.no_wa ? poi.no_wa.replace(/\D/g, '') : '';
const waBtn = noWa
? `
💬 Chat WhatsApp
`
: `
Tidak ada nomor WA
`;
const buka24Badge = isOpen
? `🟢 Buka 24 Jam`
: `🔴 Tidak 24 Jam`;
marker.bindPopup(`
`, { maxWidth: 300 });
layerGroup.addLayer(marker);
}
// ── Load semua POI dari server ──────────────────
function loadData() {
layerGroup.clearLayers();
allMarkers = {};
fetch('api/point/ambil.php?_=' + Date.now(), { cache: 'no-store' })
.then(r => r.json())
.then(j => {
if (j.status !== 'success') throw new Error(j.message);
updateCount(j.total, '📍');
j.data.forEach(addMarkerToMap);
refreshPointList(j.data);
})
.catch(err => {
showToast('Gagal memuat data POI.', 'error');
console.error(err);
});
}
// ── Refresh panel list Lokasi Usaha ──────────────────
function refreshPointList(data) {
if (typeof window.dlRefreshList !== 'function') return;
const items = (data || []).map(poi => ({
id: poi.id,
name: poi.nama_tempat,
badge: Number(poi.buka_24jam) === 1 ? '24 Jam' : 'Non-24',
badgeColor: Number(poi.buka_24jam) === 1 ? '#2ea043' : '#f85149',
dotColor: Number(poi.buka_24jam) === 1 ? '#2ea043' : '#f85149'
}));
window.dlRefreshList('Point', items);
}
// ── Hapus marker ────────────────────────────────────
window._pointHapus = function (id, btnEl) {
showDeleteConfirm('Yakin ingin menghapus lokasi ini?').then(confirmed => {
if (!confirmed) return;
btnEl.disabled = true;
btnEl.textContent = '⏳ Menghapus...';
const fd = new FormData();
fd.append('id', id);
fetch('api/point/hapus.php', { method: 'POST', body: fd })
.then(r => r.json())
.then(j => {
if (j.status === 'success') {
map.closePopup();
if (allMarkers[id]) { layerGroup.removeLayer(allMarkers[id]); delete allMarkers[id]; }
updateCount(Math.max(0, Object.keys(allMarkers).length), '📍');
// rebuild list dari allMarkers (ambil nama dari marker)
const remaining = Object.keys(allMarkers).map(k => ({
id: k,
name: allMarkers[k]._poiNama || ('#' + k),
badge: allMarkers[k]._poiBuka ? '24 Jam' : 'Non-24',
badgeColor: allMarkers[k]._poiBuka ? '#2ea043' : '#f85149',
dotColor: allMarkers[k]._poiBuka ? '#2ea043' : '#f85149'
}));
if (typeof window.dlRefreshList === 'function') window.dlRefreshList('Point', remaining);
showToast('Lokasi berhasil dihapus.');
} else throw new Error(j.message);
})
.catch(err => {
showToast(err.message || 'Gagal menghapus.', 'error');
btnEl.disabled = false;
btnEl.textContent = '🗑 Hapus Lokasi';
});
});
};
// ── Klik peta = form tambah POI ──────────────────
function onMapClick(e) {
if (currentMode !== 1) return;
const lat = e.latlng.lat.toFixed(8);
const lng = e.latlng.lng.toFixed(8);
if (tempMarker) map.removeLayer(tempMarker);
tempMarker = L.marker([lat, lng], { icon: iconTemp, pane: 'drawPane' }).addTo(map);
L.popup({ maxWidth: 320, closeOnClick: false })
.setLatLng(e.latlng)
.setContent(`
`)
.openOn(map);
setTimeout(() => { const el = document.getElementById('f_nama'); if (el) el.focus(); }, 200);
}
// ── Simpan POI ────────────────────────────────────
window._pointSimpan = function () {
const nama = document.getElementById('f_nama').value.trim();
const wa = document.getElementById('f_wa').value.trim();
const buka24 = document.getElementById('f_buka24').value;
const lat = document.getElementById('f_lat').value;
const lng = document.getElementById('f_lng').value;
const status = document.getElementById('poiStatus');
const btn = document.getElementById('btnSimpanPoi');
if (!nama) {
status.textContent = '⚠ Nama tempat wajib diisi.';
status.className = 'form-status error';
document.getElementById('f_nama').focus();
return;
}
btn.disabled = true;
btn.textContent = '⏳ Menyimpan...';
const fd = new FormData();
fd.append('nama_tempat', nama);
fd.append('no_wa', wa);
fd.append('buka_24jam', buka24);
fd.append('latitude', lat);
fd.append('longitude', lng);
fetch('api/point/simpan.php', { method: 'POST', body: fd })
.then(r => r.json())
.then(j => {
if (j.status === 'success') {
map.closePopup();
if (tempMarker) { map.removeLayer(tempMarker); tempMarker = null; }
addMarkerToMap(j.data);
updateCount(Object.keys(allMarkers).length, '📍');
// Tambahkan item baru ke list
const allItems = Object.values(allMarkers).map(m => ({
id: m._poiId,
name: m._poiNama || ('#' + m._poiId),
badge: m._poiBuka ? '24 Jam' : 'Non-24',
badgeColor: m._poiBuka ? '#2ea043' : '#f85149',
dotColor: m._poiBuka ? '#2ea043' : '#f85149'
}));
if (typeof window.dlRefreshList === 'function') window.dlRefreshList('Point', allItems);
showToast(`"${escapeHTML(nama)}" berhasil disimpan!`);
} else throw new Error(j.message);
})
.catch(err => {
status.textContent = '✕ ' + err.message;
status.className = 'form-status error';
btn.disabled = false;
btn.textContent = '💾 Simpan Lokasi';
});
};
// ── Init / cleanup ────────────────────────────────────
window.initPoint = function () {
if (active) { /* already added to map, just refresh data if needed */ loadData(); return; }
active = true;
layerGroup.addTo(map);
map.on('click', onMapClick);
// Daftarkan fungsi focus untuk panel list
window._dlFocusFns['Point'] = function(id) {
const marker = allMarkers[id];
if (!marker) return;
map.setView(marker.getLatLng(), Math.max(map.getZoom(), 17), { animate: true });
setTimeout(() => marker.openPopup(), 350);
};
loadData();
};
// Filter Toggle
window._pointToggleLayer = function(visible) {
if (visible) {
map.addLayer(layerGroup);
} else {
map.removeLayer(layerGroup);
// Juga tutup popup & bersihkan titik sementara jika ada
if (tempMarker) { map.removeLayer(tempMarker); tempMarker = null; }
}
};
})();