feat: implement full authentication system and CRUD APIs for users, rumah ibadah, and penduduk miskin with database updates.
This commit is contained in:
@@ -95,7 +95,9 @@ function addIbadahMarker(item) {
|
||||
|
||||
if (isNaN(lat) || isNaN(lng)) return;
|
||||
|
||||
const marker = L.marker([lat, lng], { icon: makeIbadahIcon(item.jenis), draggable: true });
|
||||
const isAdmin = !!(window.currentUser && window.currentUser.role === 'admin');
|
||||
|
||||
const marker = L.marker([lat, lng], { icon: makeIbadahIcon(item.jenis), draggable: isAdmin });
|
||||
|
||||
// Lingkaran radius
|
||||
const circle = L.circle([lat, lng], {
|
||||
@@ -107,7 +109,7 @@ function addIbadahMarker(item) {
|
||||
});
|
||||
|
||||
circle.on('mousemove', function(e) {
|
||||
if (isResizing) return;
|
||||
if (!isAdmin || isResizing) return;
|
||||
const center = circle.getLatLng();
|
||||
const radius = circle.getRadius();
|
||||
const dist = center.distanceTo(e.latlng);
|
||||
@@ -125,7 +127,7 @@ function addIbadahMarker(item) {
|
||||
});
|
||||
|
||||
circle.on('mousedown', function(e) {
|
||||
if (circle.nearEdge) {
|
||||
if (isAdmin && circle.nearEdge) {
|
||||
map.dragging.disable();
|
||||
isResizing = true;
|
||||
resizingCircle = circle;
|
||||
@@ -139,16 +141,22 @@ function addIbadahMarker(item) {
|
||||
|
||||
const d = item;
|
||||
const emot = IBADAH_EMOJI_MAP[d.jenis] || '🕌';
|
||||
let actionButtons = '';
|
||||
if (isAdmin) {
|
||||
actionButtons = `
|
||||
<div style="display:flex; gap:5px;">
|
||||
<button style="padding:4px 8px; background:#007bff; color:white; border:none; border-radius:3px; cursor:pointer;" onclick="openEditIbadahModal(${d.id})">Edit</button>
|
||||
<button style="padding:4px 8px; background:#dc3545; color:white; border:none; border-radius:3px; cursor:pointer;" onclick="deleteIbadah(${d.id})">Hapus</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
const popupContent = `
|
||||
<div style="font-family: Arial, sans-serif; min-width: 160px;">
|
||||
<h4 style="margin:0 0 5px 0;">${emot} ${d.nama}</h4>
|
||||
<p style="margin: 0 0 3px 0;"><b>Jenis:</b> ${d.jenis || 'Masjid'}</p>
|
||||
<p style="margin: 0 0 3px 0;"><b>Alamat:</b> ${d.alamat}</p>
|
||||
<p style="margin: 0 0 10px 0;"><b>Radius:</b> ${d.radius} m</p>
|
||||
<div style="display:flex; gap:5px;">
|
||||
<button style="padding:4px 8px; background:#007bff; color:white; border:none; border-radius:3px; cursor:pointer;" onclick="openEditIbadahModal(${d.id})">Edit</button>
|
||||
<button style="padding:4px 8px; background:#dc3545; color:white; border:none; border-radius:3px; cursor:pointer;" onclick="deleteIbadah(${d.id})">Hapus</button>
|
||||
</div>
|
||||
${actionButtons}
|
||||
</div>
|
||||
`;
|
||||
marker.bindPopup(popupContent);
|
||||
@@ -168,7 +176,9 @@ function addIbadahMarker(item) {
|
||||
|
||||
// Konteks Menu untuk Tambah Penduduk Miskin (klik kanan peta)
|
||||
map.on('contextmenu', function(e) {
|
||||
if (isDrawingMode) return;
|
||||
|
||||
const canManage = !!(window.currentUser && (window.currentUser.role === 'admin' || window.currentUser.role === 'pengelola'));
|
||||
if (!canManage) return;
|
||||
|
||||
const popupContent = `
|
||||
<div class="popup-form">
|
||||
@@ -181,8 +191,6 @@ map.on('contextmenu', function(e) {
|
||||
|
||||
// Map Click -> Form Add Rumah Ibadah
|
||||
map.on('click', function(e) {
|
||||
if (isDrawingMode) return;
|
||||
|
||||
if (window.currentAddMode === 'rumah_ibadah') {
|
||||
const lat = e.latlng.lat;
|
||||
const lng = e.latlng.lng;
|
||||
@@ -389,19 +397,55 @@ function addMiskinMarker(item) {
|
||||
const lng = parseFloat(item.lng);
|
||||
if (isNaN(lat) || isNaN(lng)) return;
|
||||
|
||||
const marker = L.marker([lat, lng], { icon: makeMiskinIcon(false), draggable: true });
|
||||
const canManage = !!(window.currentUser && (window.currentUser.role === 'admin' || window.currentUser.role === 'pengelola'));
|
||||
|
||||
const marker = L.marker([lat, lng], { icon: makeMiskinIcon(false), draggable: canManage });
|
||||
marker.miskinData = item;
|
||||
|
||||
const d = item;
|
||||
let actionButtons = '';
|
||||
if (canManage) {
|
||||
actionButtons = `
|
||||
<button style="padding:4px 8px; background:#007bff; color:white; border:none; border-radius:3px; cursor:pointer;" onclick="openEditMiskinModal(${d.id})">Edit</button>
|
||||
<button style="padding:4px 8px; background:#dc3545; color:white; border:none; border-radius:3px; cursor:pointer;" onclick="deleteMiskin(${d.id})">Hapus</button>
|
||||
`;
|
||||
}
|
||||
|
||||
let photoLinksHtml = '';
|
||||
if (d.foto_rumah) {
|
||||
photoLinksHtml += `
|
||||
<div style="margin: 5px 0;">
|
||||
<b style="font-size:11px;">Foto Rumah:</b><br>
|
||||
<a href="/poverty/uploads/${d.foto_rumah}" target="_blank">
|
||||
<img src="/poverty/uploads/${d.foto_rumah}" alt="Foto Rumah"
|
||||
style="max-width:150px; max-height:100px; border-radius:4px; margin-top:3px; border:1px solid #ddd; object-fit:cover; cursor:pointer;"
|
||||
onerror="this.style.display='none'; this.nextElementSibling.style.display='inline';"/>
|
||||
<span style="display:none; font-size:11px; color:#ef4444;">❌ Foto tidak dapat dimuat</span>
|
||||
</a>
|
||||
</div>`;
|
||||
}
|
||||
if (d.foto_kk) {
|
||||
photoLinksHtml += `
|
||||
<div style="margin: 5px 0;">
|
||||
<b style="font-size:11px;">Foto KK:</b><br>
|
||||
<a href="/poverty/uploads/${d.foto_kk}" target="_blank">
|
||||
<img src="/poverty/uploads/${d.foto_kk}" alt="Foto KK"
|
||||
style="max-width:150px; max-height:100px; border-radius:4px; margin-top:3px; border:1px solid #ddd; object-fit:cover; cursor:pointer;"
|
||||
onerror="this.style.display='none'; this.nextElementSibling.style.display='inline';"/>
|
||||
<span style="display:none; font-size:11px; color:#ef4444;">❌ Foto tidak dapat dimuat</span>
|
||||
</a>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const popupContent = `
|
||||
<div style="font-family: Arial, sans-serif; min-width: 165px;">
|
||||
<h4 style="margin:0 0 5px 0;">🏠 ${d.nama}</h4>
|
||||
<p style="margin: 0 0 3px 0;"><b>Bantuan:</b> ${d.kategori_bantuan}</p>
|
||||
<p style="margin: 0 0 10px 0;"><b>Jiwa:</b> ${d.jumlah_jiwa || '-'}</p>
|
||||
<div style="display:flex; gap:5px; flex-wrap:wrap;">
|
||||
<p style="margin: 0 0 5px 0;"><b>Jiwa:</b> ${d.jumlah_jiwa || '-'}</p>
|
||||
${photoLinksHtml}
|
||||
<div style="display:flex; gap:5px; flex-wrap:wrap; margin-top:8px;">
|
||||
<button style="padding:4px 8px; background:#6366f1; color:white; border:none; border-radius:3px; cursor:pointer; font-size:11px;" onclick="openLogBantuan(${d.id}, '${d.nama.replace(/'/g, "\\'")}');">📋 Log Bantuan</button>
|
||||
<button style="padding:4px 8px; background:#007bff; color:white; border:none; border-radius:3px; cursor:pointer;" onclick="openEditMiskinModal(${d.id})">Edit</button>
|
||||
<button style="padding:4px 8px; background:#dc3545; color:white; border:none; border-radius:3px; cursor:pointer;" onclick="deleteMiskin(${d.id})">Hapus</button>
|
||||
${actionButtons}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -445,6 +489,14 @@ window.formAddMiskin = function(lat, lng) {
|
||||
<label>Jumlah Jiwa</label>
|
||||
<input type="number" id="miskinJiwa" value="1" min="1">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Foto Rumah</label>
|
||||
<input type="file" id="miskinFotoRumah" accept="image/*">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Foto Kartu Keluarga (KK)</label>
|
||||
<input type="file" id="miskinFotoKK" accept="image/*">
|
||||
</div>
|
||||
`;
|
||||
openModal("Tambah Penduduk Miskin", bodyHTML, function() {
|
||||
window.saveNewMiskin(lat, lng);
|
||||
@@ -455,13 +507,23 @@ window.saveNewMiskin = function(lat, lng) {
|
||||
const nama = document.getElementById('miskinNama').value;
|
||||
const kategori_bantuan = document.getElementById('miskinKategori').value;
|
||||
const jumlah_jiwa = document.getElementById('miskinJiwa').value;
|
||||
const fotoRumahInput = document.getElementById('miskinFotoRumah');
|
||||
const fotoKKInput = document.getElementById('miskinFotoKK');
|
||||
|
||||
if (!nama) { alert('Nama harus diisi!'); return; }
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('nama', nama);
|
||||
formData.append('kategori_bantuan', kategori_bantuan);
|
||||
formData.append('jumlah_jiwa', jumlah_jiwa);
|
||||
formData.append('lat', lat);
|
||||
formData.append('lng', lng);
|
||||
if (fotoRumahInput.files[0]) formData.append('foto_rumah', fotoRumahInput.files[0]);
|
||||
if (fotoKKInput.files[0]) formData.append('foto_kk', fotoKKInput.files[0]);
|
||||
|
||||
fetch('api/penduduk_miskin/create.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ nama, kategori_bantuan, jumlah_jiwa, lat, lng })
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
@@ -495,6 +557,32 @@ window.openEditMiskinModal = function(id) {
|
||||
<label>Jumlah Jiwa</label>
|
||||
<input type="number" id="editMiskinJiwa" value="${d.jumlah_jiwa || 1}" min="1">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Foto Rumah</label>
|
||||
<input type="file" id="editMiskinFotoRumah" accept="image/*">
|
||||
${d.foto_rumah ? `
|
||||
<div style="margin-top:5px;">
|
||||
<a href="/poverty/uploads/${d.foto_rumah}" target="_blank">
|
||||
<img src="/poverty/uploads/${d.foto_rumah}" alt="Foto Rumah" style="max-width:120px; max-height:80px; border-radius:4px; border:1px solid #ddd; object-fit:cover;"
|
||||
onerror="this.style.display='none'; this.nextElementSibling.style.display='inline';"/>
|
||||
<span style="display:none; font-size:11px; color:#ef4444;">❌ File gambar rusak atau tidak ditemukan</span>
|
||||
</a>
|
||||
<div style="font-size:11px;color:#888;margin-top:2px;">Upload baru untuk mengganti</div>
|
||||
</div>` : ''}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Foto Kartu Keluarga (KK)</label>
|
||||
<input type="file" id="editMiskinFotoKK" accept="image/*">
|
||||
${d.foto_kk ? `
|
||||
<div style="margin-top:5px;">
|
||||
<a href="/poverty/uploads/${d.foto_kk}" target="_blank">
|
||||
<img src="/poverty/uploads/${d.foto_kk}" alt="Foto KK" style="max-width:120px; max-height:80px; border-radius:4px; border:1px solid #ddd; object-fit:cover;"
|
||||
onerror="this.style.display='none'; this.nextElementSibling.style.display='inline';"/>
|
||||
<span style="display:none; font-size:11px; color:#ef4444;">❌ File gambar rusak atau tidak ditemukan</span>
|
||||
</a>
|
||||
<div style="font-size:11px;color:#888;margin-top:2px;">Upload baru untuk mengganti</div>
|
||||
</div>` : ''}
|
||||
</div>
|
||||
`;
|
||||
map.closePopup();
|
||||
openModal("Edit Penduduk Miskin", bodyHTML, function() {
|
||||
@@ -506,10 +594,22 @@ window.saveEditMiskin = function(id, lat, lng, namaId, kategoriId, jiwaId) {
|
||||
const nama = document.getElementById(namaId).value;
|
||||
const kategori_bantuan = document.getElementById(kategoriId).value;
|
||||
const jumlah_jiwa = jiwaId ? document.getElementById(jiwaId).value : 1;
|
||||
const fotoRumahInput = document.getElementById('editMiskinFotoRumah');
|
||||
const fotoKKInput = document.getElementById('editMiskinFotoKK');
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('id', id);
|
||||
formData.append('nama', nama);
|
||||
formData.append('kategori_bantuan', kategori_bantuan);
|
||||
formData.append('jumlah_jiwa', jumlah_jiwa);
|
||||
formData.append('lat', lat);
|
||||
formData.append('lng', lng);
|
||||
if (fotoRumahInput.files[0]) formData.append('foto_rumah', fotoRumahInput.files[0]);
|
||||
if (fotoKKInput.files[0]) formData.append('foto_kk', fotoKKInput.files[0]);
|
||||
|
||||
fetch('api/penduduk_miskin/update.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id, nama, kategori_bantuan, jumlah_jiwa, lat, lng })
|
||||
body: formData
|
||||
}).then(res => res.json()).then(data => {
|
||||
if(data.status === 'success') { closeModal(); loadPendudukMiskin(); }
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user