Memperbarui UI/UX

This commit is contained in:
2026-06-07 23:32:06 +07:00
parent f7479770e6
commit 76a8782409
47 changed files with 4378 additions and 685 deletions
+426 -147
View File
@@ -5,196 +5,408 @@
</h2>
</x-slot>
<div class="py-12">
<div class="py-8">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900 dark:text-gray-100">
<div class="bg-white/80 dark:bg-slate-900/80 backdrop-blur-xl overflow-hidden shadow-2xl sm:rounded-3xl border border-slate-200/50 dark:border-slate-800/50">
<div class="p-6 sm:p-10 text-slate-900 dark:text-slate-100">
<!-- Map Interface Start -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
#map { height: 450px; border-radius: 12px; margin-bottom: 20px; border: 2px solid #333; z-index: 1; }
.panel { background: #f4f7f6; padding: 20px; border-radius: 12px; margin-bottom: 15px; color: black;}
.edit-form { background: #fff3cd; padding: 15px; border-radius: 12px; display: none; margin-bottom: 15px; border: 1px solid #ffeeba; color: black; }
#map { z-index: 1; }
.leaflet-popup-content-wrapper { border-radius: 1rem; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1); border: 1px solid rgba(255,255,255,0.2); backdrop-filter: blur(8px); }
.leaflet-popup-content { text-align: center; color: #0f172a; font-family: 'Inter', ui-sans-serif, system-ui, sans-serif; font-weight: 500;}
.popup-slider { width: 100%; margin-top: 10px; accent-color: #6366f1; }
.map-table { width: 100%; border-collapse: collapse; background: white; color: black; }
.map-table th, .map-table td { padding: 12px; border: 1px solid #ddd; text-align: left; }
.map-table th { background: #007bff; color: white; }
.btn-edit { background: #ffc107; color: #000; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer; text-decoration: none; font-size: 13px; }
.btn-delete { background: #dc3545; color: #fff; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer; text-decoration: none; font-size: 13px; }
.leaflet-popup-content { text-align: center; color: black; }
.popup-slider { width: 100%; }
/* Ubah kursor peta menjadi crosshair untuk menandakan mode tambah titik */
/* Crosshair when adding point */
.mode-tambah .leaflet-container { cursor: crosshair !important; }
/* Custom form inputs to match Tailwind forms plugin if not installed */
.form-input { display: block; width: 100%; border-radius: 0.75rem; border: 1px solid #e2e8f0; padding: 0.75rem 1rem; font-size: 0.875rem; line-height: 1.25rem; transition: all 0.2s ease-in-out; background-color: rgba(255, 255, 255, 0.5); color: #0f172a; backdrop-filter: blur(8px); }
.form-input:focus { outline: none; border-color: #6366f1; box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.15); background-color: #fff; }
.dark .form-input { background-color: rgba(30, 41, 59, 0.5); border-color: #334155; color: #f8fafc; }
.dark .form-input:focus { border-color: #818cf8; box-shadow: 0 0 0 4px rgba(129, 140, 248, 0.15); background-color: #1e293b; }
</style>
<div class="panel">
<strong style="display: block; margin-bottom: 10px;">Tambah Titik Baru:</strong>
<div style="display: flex; gap: 10px; align-items: center; flex-wrap: wrap;">
<input type="text" id="nama" placeholder="Masukkan Nama..." style="padding: 10px; border-radius: 6px; border: 1px solid #ccc; color: black; flex-grow: 1; max-width: 300px;">
<input type="hidden" id="mode" value="">
<button type="button" id="btn-mode-ibadah" onclick="setMode('ibadah')" style="padding: 10px 15px; background: #e2e8f0; color: #333; border: none; border-radius: 6px; font-weight: bold; cursor: pointer; transition: 0.3s;">
🏛️ Tempat Ibadah
</button>
<button type="button" id="btn-mode-penerima" onclick="setMode('penerima')" style="padding: 10px 15px; background: #e2e8f0; color: #333; border: none; border-radius: 6px; font-weight: bold; cursor: pointer; transition: 0.3s;">
🏠 Penerima Bantuan
</button>
@php
$total_penerima = $penerimas->count();
$sudah_cair = 0;
$belum_cair = 0;
$current_month = now()->format('Y-m');
foreach($penerimas as $p) {
if ($p->tanggal_pencairan_terakhir && $p->tanggal_pencairan_terakhir->format('Y-m') === $current_month) {
$sudah_cair++;
} else {
$belum_cair++;
}
}
@endphp
<!-- Top Action Bar -->
<div class="flex flex-col lg:flex-row lg:items-stretch gap-6 mb-8">
<!-- Add Button -->
<button id="btn-toggle-form" class="w-full lg:w-1/4 flex-shrink-0 flex items-center justify-center px-6 py-4 border border-transparent text-base font-semibold rounded-2xl shadow-lg shadow-indigo-500/30 text-white bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-500 hover:to-purple-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hover:-translate-y-1 transition-all duration-300">
<svg id="btn-icon-plus" class="w-6 h-6 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
<svg id="btn-icon-minus" class="w-6 h-6 mr-2 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4"></path></svg>
<span id="btn-text">Tambah Data Baru</span>
</button>
<!-- Stats Panel -->
<div class="flex-grow flex bg-white/50 dark:bg-slate-800/50 backdrop-blur-md rounded-2xl shadow-sm border border-slate-200 dark:border-slate-700 overflow-hidden divide-x divide-slate-200/50 dark:divide-slate-700/50">
<div class="flex-1 p-4 flex flex-col justify-center items-center hover:bg-slate-50/50 dark:hover:bg-slate-800/80 transition-colors">
<span class="text-xs font-semibold text-slate-500 dark:text-slate-400 uppercase tracking-widest mb-1 text-center">Total Penerima</span>
<span class="text-3xl font-extrabold bg-clip-text text-transparent bg-gradient-to-r from-indigo-600 to-purple-600 dark:from-indigo-400 dark:to-purple-400">{{ $total_penerima }}</span>
</div>
<div class="flex-1 p-4 flex flex-col justify-center items-center bg-gradient-to-b from-emerald-50/50 to-emerald-100/50 dark:from-emerald-900/10 dark:to-emerald-800/10 hover:from-emerald-100/50 hover:to-emerald-200/50 transition-colors">
<span class="text-xs font-semibold text-emerald-600 dark:text-emerald-400 uppercase tracking-widest mb-1 text-center">Sudah Cair</span>
<span class="text-3xl font-extrabold text-emerald-600 dark:text-emerald-400">{{ $sudah_cair }}</span>
</div>
<div class="flex-1 p-4 flex flex-col justify-center items-center bg-gradient-to-b from-rose-50/50 to-rose-100/50 dark:from-rose-900/10 dark:to-rose-800/10 hover:from-rose-100/50 hover:to-rose-200/50 transition-colors">
<span class="text-xs font-semibold text-rose-600 dark:text-rose-400 uppercase tracking-widest mb-1 text-center">Belum Cair</span>
<span class="text-3xl font-extrabold text-rose-600 dark:text-rose-400">{{ $belum_cair }}</span>
</div>
</div>
</div>
<!-- Add Form Container -->
<div id="form-container" class="hidden bg-white/60 dark:bg-slate-800/60 backdrop-blur-xl rounded-3xl border border-slate-200 dark:border-slate-700 p-6 md:p-8 mb-8 shadow-xl transition-all duration-500 transform origin-top">
<div class="flex items-center mb-6 border-b border-slate-200 dark:border-slate-700 pb-4">
<div class="w-12 h-12 rounded-2xl bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center text-white shadow-lg shadow-indigo-500/30 mr-4 shrink-0">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>
</div>
<h3 class="text-2xl font-bold font-outfit text-slate-900 dark:text-white tracking-tight">Lengkapi Data Lokasi</h3>
</div>
<!-- Extra Fields for Ibadah -->
<div id="fields-ibadah" style="display:none; margin-top:10px; gap: 10px; flex-wrap: wrap;">
<select id="jenis_tempat_ibadah" style="padding: 10px; border-radius: 6px; border: 1px solid #ccc; color: black;">
<option value="">- Pilih Jenis Tempat Ibadah -</option>
<option value="Masjid">Masjid</option>
<option value="Gereja Katolik">Gereja Katolik</option>
<option value="Gereja Protestan">Gereja Protestan</option>
<option value="Vihara">Vihara</option>
<option value="Pura">Pura</option>
<option value="Klenteng">Klenteng</option>
</select>
<input type="text" id="kontak_person" placeholder="Kontak Person..." style="padding: 10px; border-radius: 6px; border: 1px solid #ccc; color: black;">
<input type="hidden" id="mode" value="{{ Auth::user()->role === 'admin' ? 'ibadah' : 'penerima' }}">
<input type="hidden" id="id_laporan_warga" value="{{ $laporan_fill ? $laporan_fill->id : '' }}">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Extra Fields for Ibadah -->
<div id="fields-ibadah" class="col-span-1 md:col-span-2 grid grid-cols-1 md:grid-cols-2 gap-6" style="display:none;">
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">Nama Tempat Ibadah <span class="text-rose-500">*</span></label>
<input type="text" id="nama_ibadah" class="form-input" placeholder="Contoh: Masjid Al-Ikhlas">
</div>
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">Jenis Tempat Ibadah <span class="text-rose-500">*</span></label>
<select id="jenis_tempat_ibadah" class="form-input">
<option value="">- Pilih Jenis Tempat Ibadah -</option>
<option value="Masjid">Masjid</option>
<option value="Gereja Katolik">Gereja Katolik</option>
<option value="Gereja Protestan">Gereja Protestan</option>
<option value="Vihara">Vihara</option>
<option value="Pura">Pura</option>
<option value="Klenteng">Klenteng</option>
</select>
</div>
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">Nama Pengurus</label>
<input type="text" id="nama_pengurus" class="form-input" placeholder="Masukkan nama pengurus">
</div>
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">Kontak Pengurus</label>
<input type="text" id="kontak_pengurus" class="form-input" placeholder="Nomor telepon/HP">
</div>
</div>
<!-- Extra Fields for Penerima -->
<div id="fields-penerima" class="col-span-1 md:col-span-2 grid grid-cols-1 md:grid-cols-2 gap-6" style="display:none;">
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">Nama Kepala Keluarga <span class="text-rose-500">*</span></label>
<input type="text" id="nama_kepala_keluarga" class="form-input" placeholder="Masukkan nama kepala keluarga" value="{{ $laporan_fill ? $laporan_fill->nama_calon : '' }}" required>
</div>
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">NIK Kepala Keluarga <span class="text-rose-500">*</span></label>
<input type="text" id="nik_kepala_keluarga" class="form-input" placeholder="16 digit NIK" maxlength="16" required>
</div>
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">Nomor Kartu Keluarga <span class="text-rose-500">*</span></label>
<input type="text" id="nomor_kk" class="form-input" placeholder="16 digit Nomor KK" maxlength="16" required>
</div>
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">Jumlah Tanggungan <span class="text-rose-500">*</span></label>
<input type="number" id="jumlah_tanggungan" class="form-input" placeholder="Jumlah anggota keluarga" min="0" value="{{ $laporan_fill ? $laporan_fill->jumlah_tanggungan : '' }}" required>
</div>
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">PDF Form Investigasi <span class="text-rose-500">*</span></label>
<input type="file" id="dokumen_laporan" accept=".pdf" class="form-input !p-1.5" required>
</div>
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">Foto Rumah <span class="text-slate-400 font-normal">(Opsional)</span></label>
<input type="file" id="foto" accept="image/*" multiple class="form-input !p-1.5">
</div>
</div>
</div>
<!-- Extra Fields for Penerima -->
<div id="fields-penerima" style="display:none; margin-top:10px; gap: 10px; flex-wrap: wrap;">
<input type="text" id="nik_kepala_keluarga" placeholder="NIK Kepala Keluarga..." style="padding: 10px; border-radius: 6px; border: 1px solid #ccc; color: black;">
<input type="text" id="nomor_kk" placeholder="Nomor KK..." style="padding: 10px; border-radius: 6px; border: 1px solid #ccc; color: black;">
<input type="number" id="jumlah_tanggungan" placeholder="Jml Tanggungan..." style="padding: 10px; border-radius: 6px; border: 1px solid #ccc; color: black; width: 150px;" min="0">
<select id="id_tempat_ibadah" style="padding: 10px; border-radius: 6px; border: 1px solid #ccc; color: black;">
<option value="">- Pilih Tempat Ibadah -</option>
@foreach($ibadahs as $ib)
<option value="{{ $ib->id }}">{{ $ib->nama_tempat }}</option>
@endforeach
</select>
<label style="display:flex; align-items:center; gap:5px; color:#333; font-weight:bold;">
Foto Rumah: <input type="file" id="foto_kondisi_rumah" accept="image/*" style="color: black;">
</label>
<div class="mt-8 p-4 bg-indigo-50/50 dark:bg-indigo-900/20 backdrop-blur-sm rounded-xl border border-indigo-100 dark:border-indigo-800/50 flex items-start">
<div class="w-8 h-8 rounded-full bg-indigo-100 dark:bg-indigo-800 flex items-center justify-center shrink-0 mr-3 mt-0.5">
<svg class="w-5 h-5 text-indigo-600 dark:text-indigo-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
</div>
<p class="text-sm text-indigo-800 dark:text-indigo-200 mt-1.5">
Setelah melengkapi formulir di atas, <strong>klik pada titik lokasi yang sesuai di peta</strong> di bawah untuk menyimpan data.
</p>
</div>
<small style="color: #666; display: block; margin-top: 10px; font-style: italic;">👉 Pilih jenis titik, isi kolom yang tersedia, lalu <b>klik pada peta</b> untuk menyimpan lokasinya.</small>
</div>
<script>
function setMode(mode) {
var currentMode = document.getElementById('mode').value;
document.addEventListener('DOMContentLoaded', function() {
@if(isset($laporan_fill))
document.getElementById('btn-toggle-form').click();
alert('Data laporan diisi otomatis. Silakan klik pada peta untuk menentukan lokasi rumah penerima bantuan, lengkapi data lainnya, lalu klik Simpan.');
@endif
});
document.getElementById('btn-toggle-form').addEventListener('click', function() {
var formContainer = document.getElementById('form-container');
var mapEl = document.getElementById('map');
var mode = document.getElementById('mode').value;
var btnText = document.getElementById('btn-text');
var btnIconPlus = document.getElementById('btn-icon-plus');
var btnIconMinus = document.getElementById('btn-icon-minus');
// Toggle off if clicking the same mode
if (currentMode === mode) {
document.getElementById('mode').value = '';
document.getElementById('btn-mode-ibadah').style.background = '#e2e8f0';
document.getElementById('btn-mode-ibadah').style.color = '#333';
document.getElementById('btn-mode-penerima').style.background = '#e2e8f0';
document.getElementById('btn-mode-penerima').style.color = '#333';
if (formContainer.classList.contains('hidden')) {
formContainer.classList.remove('hidden');
btnText.innerText = 'Batal Tambah Data';
this.classList.replace('bg-indigo-600', 'bg-red-500');
this.classList.replace('hover:bg-indigo-700', 'hover:bg-red-600');
this.classList.replace('focus:ring-indigo-500', 'focus:ring-red-500');
btnIconPlus.classList.add('hidden');
btnIconMinus.classList.remove('hidden');
if(mode === 'ibadah') {
document.getElementById('fields-ibadah').style.display = 'grid';
document.getElementById('fields-penerima').style.display = 'none';
} else {
document.getElementById('fields-ibadah').style.display = 'none';
document.getElementById('fields-penerima').style.display = 'grid';
}
mapEl.classList.add('mode-tambah');
} else {
formContainer.classList.add('hidden');
btnText.innerText = 'Tambah Data Baru';
this.classList.replace('bg-red-500', 'bg-indigo-600');
this.classList.replace('hover:bg-red-600', 'hover:bg-indigo-700');
this.classList.replace('focus:ring-red-500', 'focus:ring-indigo-500');
btnIconMinus.classList.add('hidden');
btnIconPlus.classList.remove('hidden');
document.getElementById('fields-ibadah').style.display = 'none';
document.getElementById('fields-penerima').style.display = 'none';
mapEl.classList.remove('mode-tambah');
return;
}
document.getElementById('mode').value = mode;
mapEl.classList.add('mode-tambah');
if(mode === 'ibadah') {
document.getElementById('btn-mode-ibadah').style.background = '#007bff';
document.getElementById('btn-mode-ibadah').style.color = 'white';
document.getElementById('btn-mode-penerima').style.background = '#e2e8f0';
document.getElementById('btn-mode-penerima').style.color = '#333';
document.getElementById('fields-ibadah').style.display = 'flex';
document.getElementById('fields-penerima').style.display = 'none';
} else {
document.getElementById('btn-mode-penerima').style.background = '#007bff';
document.getElementById('btn-mode-penerima').style.color = 'white';
document.getElementById('btn-mode-ibadah').style.background = '#e2e8f0';
document.getElementById('btn-mode-ibadah').style.color = '#333';
document.getElementById('fields-ibadah').style.display = 'none';
document.getElementById('fields-penerima').style.display = 'flex';
}
}
});
</script>
<div id="panel-edit" class="edit-form">
<form action="{{ route('map.edit') }}" method="POST">
<!-- Edit Data Panel (Map specific) -->
<div id="panel-edit" class="hidden bg-amber-50/80 dark:bg-amber-900/20 backdrop-blur-md border border-amber-200/50 dark:border-amber-700/50 rounded-3xl p-6 md:p-8 mb-8 shadow-lg transition-all duration-300">
<div class="flex items-center mb-6 border-b border-amber-200/50 dark:border-amber-700/50 pb-4">
<div class="w-12 h-12 rounded-2xl bg-gradient-to-br from-amber-400 to-orange-500 flex items-center justify-center text-white shadow-lg shadow-amber-500/30 mr-4 shrink-0">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2-2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path></svg>
</div>
<h3 class="text-2xl font-bold font-outfit text-slate-900 dark:text-white tracking-tight">Edit Data Lokasi Peta</h3>
</div>
<form action="{{ route('map.edit') }}" method="POST" class="grid grid-cols-1 md:grid-cols-2 gap-6">
@csrf
<strong>Edit Data:</strong>
<input type="hidden" name="id" id="edit-id">
<input type="hidden" name="type" id="edit-type">
<input type="text" name="nama" id="edit-nama" placeholder="Nama" style="padding: 8px; border-radius: 4px; border: 1px solid #ccc; color: black;">
<input type="text" name="alamat" id="edit-alamat" placeholder="Alamat" style="padding: 8px; width: 400px; border-radius: 4px; border: 1px solid #ccc; color: black;">
<button type="submit" style="padding: 8px 15px; background: #28a745; color: white; border: none; border-radius: 4px;">Simpan</button>
<button type="button" onclick="closeEdit()" style="padding: 8px 15px; background: #6c757d; color: white; border: none; border-radius: 4px;">Batal</button>
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">Nama</label>
<input type="text" name="nama" id="edit-nama" class="form-input" placeholder="Nama">
</div>
<div>
<label class="block text-sm font-semibold text-slate-700 dark:text-slate-300 mb-1.5">Alamat Lengkap</label>
<input type="text" name="alamat" id="edit-alamat" class="form-input" placeholder="Alamat">
</div>
<div class="col-span-1 md:col-span-2 flex justify-end space-x-4 mt-4">
<button type="button" onclick="closeEdit()" class="px-6 py-2.5 bg-white/80 dark:bg-slate-700/80 backdrop-blur-sm border border-slate-300 dark:border-slate-600 text-slate-700 dark:text-slate-200 rounded-full hover:bg-slate-50 dark:hover:bg-slate-600 font-medium transition-all shadow-sm">Batal</button>
<button type="submit" class="px-6 py-2.5 bg-gradient-to-r from-amber-500 to-orange-500 hover:from-amber-400 hover:to-orange-400 text-white rounded-full font-medium shadow-lg shadow-amber-500/30 hover:-translate-y-0.5 transition-all">Simpan Perubahan</button>
</div>
</form>
</div>
<div id="map"></div>
<!-- The Map Layout -->
<div class="{{ Auth::user()->role === 'user' ? 'flex flex-col lg:flex-row gap-6 items-stretch' : '' }}">
<!-- Map Column -->
<div class="{{ Auth::user()->role === 'user' ? 'flex-grow lg:w-2/3 flex flex-col' : '' }}">
<div class="rounded-3xl overflow-hidden shadow-xl shadow-slate-200/50 dark:shadow-slate-900/50 border border-slate-200/80 dark:border-slate-700/80 relative {{ Auth::user()->role === 'user' ? 'flex-grow min-h-[500px]' : '' }} bg-slate-100 dark:bg-slate-800 z-10">
<div id="map" class="{{ Auth::user()->role === 'user' ? 'absolute inset-0 w-full h-full' : 'w-full' }}" style="{{ Auth::user()->role !== 'user' ? 'height: 550px;' : '' }}"></div>
</div>
</div>
<!-- Info Column (User Only) -->
@if(Auth::user()->role === 'user')
<div class="w-full lg:w-1/3 flex flex-col">
<div class="bg-white/60 dark:bg-slate-800/60 backdrop-blur-xl border border-slate-200/80 dark:border-slate-700/80 rounded-3xl shadow-xl shadow-slate-200/50 dark:shadow-slate-900/50 overflow-hidden flex flex-col h-full min-h-[500px] max-h-[500px]">
<div class="bg-indigo-50/80 dark:bg-indigo-900/40 backdrop-blur-sm px-6 py-5 border-b border-indigo-100 dark:border-indigo-800/50 flex justify-between items-center shrink-0">
<h3 class="font-bold font-outfit text-xl text-slate-900 dark:text-white tracking-tight truncate">Tempat Ibadah Anda</h3>
</div>
<div class="p-6 flex-grow overflow-y-auto">
@forelse($ibadahs as $index => $ib)
<div class="mb-6 last:mb-0 bg-white dark:bg-slate-700/50 p-5 rounded-2xl border border-slate-100 dark:border-slate-600 shadow-sm">
<h4 class="font-bold text-lg text-slate-900 dark:text-white mb-2">{{ $ib->nama_tempat }}</h4>
<span class="inline-block px-3 py-1.5 bg-indigo-100 text-indigo-700 dark:bg-indigo-500/20 dark:text-indigo-300 text-xs font-bold rounded-full mb-4">{{ $ib->jenis_tempat_ibadah ?? 'Lainnya' }}</span>
<div class="space-y-3 text-sm text-slate-600 dark:text-slate-300">
<div class="flex justify-between border-b border-slate-100 dark:border-slate-600/50 pb-1.5">
<span class="text-slate-500 font-medium">Pengurus</span>
<span class="text-slate-900 dark:text-slate-200">{{ $ib->nama_pengurus ?? '-' }}</span>
</div>
<div class="flex justify-between border-b border-slate-100 dark:border-slate-600/50 pb-1.5">
<span class="text-slate-500 font-medium">Kontak</span>
<span class="text-slate-900 dark:text-slate-200">{{ $ib->kontak_pengurus ?? '-' }}</span>
</div>
<div class="flex justify-between border-b border-slate-100 dark:border-slate-600/50 pb-1.5">
<span class="text-slate-500 font-medium">Radius</span>
<span class="text-slate-900 dark:text-slate-200 font-bold text-indigo-600 dark:text-indigo-400">{{ $ib->radius_meter }} m</span>
</div>
<div class="flex flex-col pt-1.5">
<span class="text-slate-500 font-medium mb-1">Alamat</span>
<span class="text-slate-900 dark:text-slate-200 leading-relaxed">{{ $ib->alamat }}</span>
</div>
</div>
<div class="mt-5 pt-4 border-t border-slate-100 dark:border-slate-600">
<button onclick='openEditIbadah({{ $ib->id }}, "{{ addslashes($ib->nama_tempat) }}", "{{ addslashes($ib->alamat) }}", {{ $ib->radius_meter }}, "{{ addslashes($ib->jenis_tempat_ibadah) }}", "{{ addslashes($ib->nama_pengurus) }}", "{{ addslashes($ib->kontak_pengurus) }}")' class="w-full inline-flex justify-center items-center px-4 py-2 border border-transparent text-sm font-semibold rounded-xl shadow-sm text-amber-800 bg-amber-100/80 hover:bg-amber-200 focus:outline-none transition-all duration-300">
<svg class="w-4 h-4 mr-1.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path></svg>
Edit Data Lokasi
</button>
</div>
</div>
@empty
<div class="flex flex-col items-center justify-center py-12 px-4 text-center">
<div class="w-16 h-16 bg-slate-100 dark:bg-slate-700 rounded-full flex items-center justify-center mb-4">
<svg class="w-8 h-8 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4M12 20V4"></path></svg>
</div>
<h4 class="text-lg font-bold text-slate-900 dark:text-white mb-1">Belum ada data</h4>
<p class="text-sm text-slate-500 dark:text-slate-400">Anda belum menambahkan lokasi tempat ibadah.</p>
</div>
@endforelse
</div>
</div>
</div>
@endif
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
var map = L.map('map').setView([-0.02, 109.34], 14);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', {
attribution: '&copy; OpenStreetMap contributors &copy; CARTO',
subdomains: 'abcd',
maxZoom: 20
}).addTo(map);
var listIbadah = [];
var listPenerima = [];
var iconIbadah = L.divIcon({
className: '',
html: `<div style="background:#007bff; color:#fff; border-radius:50%; width:30px; height:30px; display:flex; align-items:center; justify-content:center; border:2px solid #fff;">🏛️</div>`,
iconSize: [30, 30]
className: 'custom-div-icon',
html: `<div class="shadow-lg" style="background:#4f46e5; color:#fff; border-radius:50%; width:36px; height:36px; display:flex; align-items:center; justify-content:center; border:3px solid #fff; font-size:16px;">🏛️</div>`,
iconSize: [36, 36],
iconAnchor: [18, 18]
});
// 1. Fungsi Edit UI
function openEdit(id, type, nama, alamat) {
document.getElementById('panel-edit').style.display = 'block';
var panel = document.getElementById('panel-edit');
panel.classList.remove('hidden');
document.getElementById('edit-id').value = id;
document.getElementById('edit-type').value = type;
document.getElementById('edit-nama').value = nama;
document.getElementById('edit-alamat').value = alamat;
window.scrollTo(0,0);
// Scroll smoothly to edit panel
panel.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
function closeEdit() { document.getElementById('panel-edit').style.display = 'none'; }
function closeEdit() { document.getElementById('panel-edit').classList.add('hidden'); }
// 2. Reverse Geocoding & Save
map.on('click', async function(e) {
const mode = document.getElementById('mode').value;
if(!mode) return; // Mode biasa, jangan lakukan apa-apa
if(document.getElementById('form-container').classList.contains('hidden')) return;
const nama = document.getElementById('nama').value;
if(!nama) return alert("Isi nama dulu!");
const res = await fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${e.latlng.lat}&lon=${e.latlng.lng}`);
const data = await res.json();
const addr = data.address || {};
const alamatDetail = [addr.road, addr.village || addr.suburb, addr.city].filter(Boolean).join(", ");
let fd = new FormData();
fd.append('_token', '{{ csrf_token() }}');
fd.append('type', mode);
fd.append('nama', nama);
fd.append('lat', e.latlng.lat);
fd.append('lng', e.latlng.lng);
fd.append('alamat', alamatDetail || data.display_name);
let nama = '';
if (mode === 'ibadah') {
fd.append('jenis_tempat_ibadah', document.getElementById('jenis_tempat_ibadah').value);
fd.append('kontak_person', document.getElementById('kontak_person').value);
nama = document.getElementById('nama_ibadah').value;
if(!nama) return alert("Isi nama tempat ibadah dulu!");
if(!document.getElementById('jenis_tempat_ibadah').value) return alert("Pilih jenis tempat ibadah!");
} else {
fd.append('nik_kepala_keluarga', document.getElementById('nik_kepala_keluarga').value);
fd.append('nomor_kk', document.getElementById('nomor_kk').value);
fd.append('jumlah_tanggungan', document.getElementById('jumlah_tanggungan').value);
fd.append('id_tempat_ibadah', document.getElementById('id_tempat_ibadah').value);
nama = document.getElementById('nama_kepala_keluarga').value;
if(!nama) return alert("Isi nama kepala keluarga (wajib)!");
const fotoInput = document.getElementById('foto_kondisi_rumah');
if (fotoInput.files.length > 0) {
fd.append('foto_kondisi_rumah', fotoInput.files[0]);
}
const nik = document.getElementById('nik_kepala_keluarga').value;
if(!nik) return alert("Isi NIK Kepala Keluarga (wajib)!");
const kk = document.getElementById('nomor_kk').value;
if(!kk) return alert("Isi Nomor KK (wajib)!");
const tgg = document.getElementById('jumlah_tanggungan').value;
if(!tgg) return alert("Isi Jumlah Tanggungan (wajib)!");
const docInput = document.getElementById('dokumen_laporan');
if(docInput.files.length === 0) return alert("PDF Form Investigasi wajib diunggah!");
}
fetch('{{ route("map.save") }}', { method: 'POST', body: fd }).then(() => location.reload());
// Loading indicator
document.body.style.cursor = 'wait';
try {
const res = await fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${e.latlng.lat}&lon=${e.latlng.lng}`);
const data = await res.json();
const addr = data.address || {};
const alamatDetail = [addr.road, addr.village || addr.suburb, addr.city].filter(Boolean).join(", ");
let fd = new FormData();
fd.append('_token', '{{ csrf_token() }}');
fd.append('type', mode);
fd.append('nama', nama);
fd.append('lat', e.latlng.lat);
fd.append('lng', e.latlng.lng);
fd.append('alamat', alamatDetail || data.display_name);
let idLaporan = document.getElementById('id_laporan_warga').value;
if (idLaporan) {
fd.append('id_laporan_warga', idLaporan);
}
if (mode === 'ibadah') {
fd.append('jenis_tempat_ibadah', document.getElementById('jenis_tempat_ibadah').value);
fd.append('nama_pengurus', document.getElementById('nama_pengurus').value);
fd.append('kontak_pengurus', document.getElementById('kontak_pengurus').value);
} else {
fd.append('nik_kepala_keluarga', document.getElementById('nik_kepala_keluarga').value);
fd.append('nomor_kk', document.getElementById('nomor_kk').value);
fd.append('jumlah_tanggungan', document.getElementById('jumlah_tanggungan').value);
const docInput = document.getElementById('dokumen_laporan');
if (docInput.files.length > 0) {
fd.append('dokumen_laporan', docInput.files[0]);
}
const fotoInput = document.getElementById('foto');
if (fotoInput.files.length > 0) {
for (let i = 0; i < fotoInput.files.length; i++) {
fd.append('foto[]', fotoInput.files[i]);
}
}
}
const saveRes = await fetch('{{ route("map.save") }}', { method: 'POST', body: fd });
const saveData = await saveRes.json();
if (saveData.status === 'error') {
alert(saveData.message);
document.body.style.cursor = 'default';
return;
}
location.reload();
} catch (err) {
alert("Terjadi kesalahan saat menyimpan data lokasi.");
document.body.style.cursor = 'default';
}
});
// 3. Load Data Ibadah
@@ -202,25 +414,31 @@
(function(){
var rAwal = {{ $ib->radius_meter }};
var circle = L.circle([{{ $ib->lat }}, {{ $ib->lng }}], {
radius: rAwal, color: 'blue', fillOpacity: 0.1
radius: rAwal, color: '#4f46e5', fillColor: '#4f46e5', fillOpacity: 0.1, weight: 2, dashArray: '5, 5'
}).addTo(map);
var marker = L.marker([{{ $ib->lat }}, {{ $ib->lng }}], {icon: iconIbadah}).addTo(map);
listIbadah.push({id: {{ $ib->id }}, nama: "{{ addslashes($ib->nama_tempat) }}", circle: circle, latlng: L.latLng({{ $ib->lat }}, {{ $ib->lng }})});
marker.bindPopup(`
<b>{{ addslashes($ib->nama_tempat) }}</b><br>
Radius: <span id="val_{{ $ib->id }}">${rAwal}</span> m<br>
<div class="text-center pb-2">
<strong class="text-gray-800 text-base block mb-1">{{ addslashes($ib->nama_tempat) }}</strong>
<span class="text-xs bg-indigo-100 text-indigo-800 px-2 py-1 rounded-full">Radius: <span id="val_{{ $ib->id }}">${rAwal}</span> m</span>
</div>
@if(Auth::user()->role !== 'user')
<input type="range" class="popup-slider" min="100" max="3000" value="${rAwal}" oninput="updateRadius(${rAwal}, this.value, {{ $ib->id }})" onchange="saveRadius(this.value, {{ $ib->id }})">
<button onclick="window.location.href='{{ route('map.delete', ['type' => 'ibadah', 'id' => $ib->id]) }}'" style="background:red; color:white; border:none; padding:5px; width:100%; cursor:pointer; margin-top:5px;">Hapus</button>
@endif
`);
})();
@endforeach
// 4. Load Data Penerima Bantuan
@foreach($penerimas as $r)
@if($r->status_persetujuan !== 'ditolak')
var rm = L.circleMarker([{{ $r->lat }}, {{ $r->lng }}], {radius: 8, color: '#fff', fillOpacity: 1, weight: 2}).addTo(map);
listPenerima.push({marker: rm, latlng: L.latLng({{ $r->lat }}, {{ $r->lng }})});
rm.bindPopup(`<strong class="text-gray-800">{{ addslashes($r->nama_kepala_keluarga) }}</strong>`);
listPenerima.push({marker: rm, latlng: L.latLng({{ $r->lat }}, {{ $r->lng }}), statusPersetujuan: "{{ $r->status_persetujuan }}"});
@endif
@endforeach
// 5. Real-time Update Logic
@@ -239,21 +457,15 @@
}
function syncUI() {
var baris = document.querySelectorAll('.baris-penerima');
baris.forEach(row => {
var rLoc = L.latLng(row.getAttribute('data-lat'), row.getAttribute('data-lng'));
var covered = [];
listIbadah.forEach(ib => { if(rLoc.distanceTo(ib.latlng) <= ib.circle.getRadius()) covered.push(ib.nama); });
row.querySelector('.status-cell').innerHTML = covered.length > 0 ?
`<span style='color:green'>✔ ${covered.join(", ")}</span>` :
`<span style='color:red'>✘ Luar Jangkauan</span>`;
});
listPenerima.forEach(penerima => {
let check = false;
listIbadah.forEach(ib => { if(penerima.latlng.distanceTo(ib.latlng) <= ib.circle.getRadius()) check = true; });
penerima.marker.setStyle({fillColor: check ? 'green' : 'red'});
let fillColor = check ? '#10b981' : '#ef4444'; // emerald-500 : red-500
if (penerima.statusPersetujuan !== 'disetujui') {
fillColor = '#f59e0b'; // amber-500
}
penerima.marker.setStyle({fillColor: fillColor});
});
}
@@ -261,6 +473,73 @@
</script>
<!-- Map Interface End -->
@if(Auth::user()->role === 'user')
<div class="mt-8 pt-8 border-t border-gray-200 dark:border-gray-700">
<!-- Edit Ibadah Form Modal/Panel -->
<div id="panel-edit-ibadah" class="hidden mt-8 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-2xl shadow-lg p-6">
<div class="flex items-center mb-5 border-b border-gray-100 dark:border-gray-700 pb-4">
<h3 class="text-xl font-bold text-gray-900 dark:text-white">Edit Data Tempat Ibadah</h3>
</div>
<form action="{{ route('map.edit') }}" method="POST">
@csrf
<input type="hidden" name="id" id="edit-ibadah-id">
<input type="hidden" name="type" id="edit-ibadah-type" value="ibadah">
<div class="grid grid-cols-1 md:grid-cols-2 gap-5 mb-6">
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Nama Tempat</label>
<input type="text" name="nama" id="edit-ibadah-nama" class="form-input" required>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Jenis Tempat Ibadah</label>
<select name="jenis_tempat_ibadah" id="edit-ibadah-jenis" class="form-input">
<option value="">- Pilih Jenis -</option>
<option value="Masjid">Masjid</option>
<option value="Gereja Katolik">Gereja Katolik</option>
<option value="Gereja Protestan">Gereja Protestan</option>
<option value="Vihara">Vihara</option>
<option value="Pura">Pura</option>
<option value="Klenteng">Klenteng</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Nama Pengurus</label>
<input type="text" name="nama_pengurus" id="edit-ibadah-nama-pengurus" class="form-input">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Kontak Pengurus</label>
<input type="text" name="kontak_pengurus" id="edit-ibadah-kontak-pengurus" class="form-input">
</div>
<div class="col-span-1 md:col-span-2">
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Alamat Lengkap</label>
<input type="text" name="alamat" id="edit-ibadah-alamat" class="form-input" required>
</div>
</div>
<div class="flex justify-end space-x-3">
<button type="button" onclick="closeEditIbadah()" class="px-5 py-2.5 bg-white dark:bg-gray-700 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-200 rounded-xl hover:bg-gray-50 dark:hover:bg-gray-600 font-medium transition-colors">Batal</button>
<button type="submit" class="px-5 py-2.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-xl font-medium shadow-sm transition-colors">Simpan Perubahan</button>
</div>
</form>
</div>
<script>
function openEditIbadah(id, nama, alamat, radius, jenis, nama_pengurus, kontak_pengurus) {
var panel = document.getElementById('panel-edit-ibadah');
panel.classList.remove('hidden');
document.getElementById('edit-ibadah-id').value = id;
document.getElementById('edit-ibadah-nama').value = nama;
document.getElementById('edit-ibadah-alamat').value = alamat;
document.getElementById('edit-ibadah-jenis').value = jenis || '';
document.getElementById('edit-ibadah-nama-pengurus').value = nama_pengurus || '';
document.getElementById('edit-ibadah-kontak-pengurus').value = kontak_pengurus || '';
panel.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
function closeEditIbadah() { document.getElementById('panel-edit-ibadah').classList.add('hidden'); }
</script>
</div>
@endif
</div>
</div>
</div>