Files
UAS_WEBGIS_CindyDyraIslamay…/03PovertyMapping/index.html
T

778 lines
44 KiB
HTML

<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<title>WebGIS Dashboard — Manajemen Data</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"/>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@300;400;500;600;700&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/style.css">
<style>
/* ── Inline component styles not yet in style.css ── */
/* Dependent entry */
.dependent-entry {
background:var(--surface-2); border:1px solid var(--border-subtle);
border-radius:var(--r); padding:10px 12px; margin-bottom:8px; position:relative;
}
.dependent-entry .dependent-number {
font-size:9px; font-weight:700; text-transform:uppercase;
letter-spacing:0.05em; color:var(--accent); margin-bottom:8px;
}
.dependent-entry .btn-remove-dependent {
position:absolute; top:8px; right:8px;
width:26px; height:26px; border-radius:50%;
border:1px solid var(--danger); background:#fff;
color:var(--danger); cursor:pointer; font-size:10px;
display:flex; align-items:center; justify-content:center;
transition:all 0.15s; touch-action:manipulation;
}
.dependent-entry .btn-remove-dependent:hover { background:#fff4f4; }
.dependent-grid { display:grid; grid-template-columns:1fr 1fr; gap:8px; }
.dependent-grid .form-group { margin-bottom:6px; }
.dependent-grid .form-group label { font-size:9.5px; margin-bottom:2px; }
.dependent-grid .form-group input,
.dependent-grid .form-group select { padding:7px 8px; font-size:14px; min-height:38px; }
.dependent-grid .form-group-full { grid-column:1/-1; }
#dependentsContainer { max-height:260px; overflow-y:auto; padding-right:4px; -webkit-overflow-scrolling:touch; }
#dependentsContainer::-webkit-scrollbar { width:3px; }
#dependentsContainer::-webkit-scrollbar-thumb { background:var(--border); border-radius:4px; }
/* Family member list */
.family-members-section { margin-top:14px; border-top:1px solid var(--border-subtle); padding-top:12px; }
.family-members-header { display:flex; justify-content:space-between; align-items:center; margin-bottom:10px; }
.family-members-header h4 { font-size:11px; font-weight:700; text-transform:uppercase; color:var(--text-secondary); }
.btn-add-member { padding:6px 12px; font-size:11px; background:var(--success); color:white; border:none; border-radius:20px; cursor:pointer; min-height:32px; touch-action:manipulation; }
.family-member-list { max-height:190px; overflow-y:auto; -webkit-overflow-scrolling:touch; }
.family-member-item { padding:9px 10px; border-bottom:1px solid var(--border-subtle); display:flex; justify-content:space-between; align-items:center; min-height:44px; }
.family-member-item:last-child { border-bottom:none; }
.family-member-info { flex:1; }
.family-member-name { font-weight:600; font-size:12px; }
.family-member-relation { font-size:10px; color:var(--text-muted); background:var(--surface-2); padding:2px 6px; border-radius:12px; margin-left:6px; }
.family-member-job, .family-member-study { font-size:9px; color:var(--text-muted); margin-left:6px; }
.family-member-actions { display:flex; gap:5px; }
.btn-edit-member, .btn-delete-member { background:none; border:none; cursor:pointer; font-size:12px; padding:5px 8px; border-radius:5px; min-height:32px; touch-action:manipulation; }
.btn-edit-member { color:var(--warning); }
.btn-delete-member { color:var(--danger); }
/* Pending badge */
.pending-badge { background:var(--danger); color:white; font-size:9px; font-weight:700; padding:1px 5px; border-radius:10px; margin-left:4px; display:inline-block; vertical-align:middle; }
.pending-badge:empty { display:none; }
/* Popup */
.popup-info { padding:14px 16px; }
.popup-info .popup-name { font-size:14px; font-weight:700; color:var(--text-primary); margin-bottom:2px; line-height:1.3; }
.popup-info .popup-hint { font-size:9.5px; color:var(--text-muted); margin-bottom:10px; }
.popup-info .popup-badges { display:flex; gap:5px; flex-wrap:wrap; margin-bottom:10px; padding-bottom:10px; border-bottom:1px solid var(--border-subtle); }
.popup-info .popup-badge { padding:3px 9px; border-radius:20px; font-size:9.5px; font-weight:700; white-space:nowrap; }
.popup-info .popup-row { display:flex; align-items:flex-start; gap:8px; margin-bottom:6px; font-size:12px; color:var(--text-secondary); }
.popup-info .popup-row i { font-size:10px; color:var(--text-muted); margin-top:2px; flex-shrink:0; width:12px; }
.popup-info .popup-row strong { color:var(--text-primary); font-weight:600; }
.popup-info .popup-section { margin-top:10px; padding:9px 11px; background:var(--surface-2); border-radius:var(--r-sm); border:1px solid var(--border-subtle); }
.popup-info .popup-section-label { font-size:9px; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; color:var(--text-muted); margin-bottom:6px; }
.popup-actions { display:flex; gap:5px; margin-top:12px; padding-top:10px; border-top:1px solid var(--border-subtle); flex-wrap:wrap; }
.popup-actions .btn { margin:0; font-size:11px; padding:7px 10px; min-height:36px; }
/* Admin */
.admin-tab-panel.active { display:block; }
.admin-tab-panel { display:none; }
.btn-approve { background:var(--success); color:white; }
.btn-approve:hover { filter:brightness(0.92); }
.btn-reject { background:var(--danger); color:white; }
.btn-reject:hover { filter:brightness(0.92); }
/* Mobile sidebar toggle button */
.sidebar-toggle {
position:absolute; top:14px; left:14px; z-index:1001;
width:42px; height:42px; border-radius:var(--r);
background:var(--surface); border:1px solid var(--border);
box-shadow:var(--shadow-md); cursor:pointer;
display:none; align-items:center; justify-content:center;
color:var(--accent); font-size:17px;
transition:all 0.15s; touch-action:manipulation;
}
.sidebar-toggle:active { transform:scale(0.94); }
@media (max-width:768px) { .sidebar-toggle { display:flex; } }
/* Sidebar backdrop */
.sidebar-backdrop {
display:none; position:fixed; inset:0;
background:rgba(10,15,28,0.45); z-index:999;
backdrop-filter:blur(2px); -webkit-backdrop-filter:blur(2px);
}
.sidebar-backdrop.active { display:block; }
/* Dashboard modal mobile close area */
#dashboardModal .modal-close-mobile {
display:none;
}
/* Legend expand toggle on mobile */
.legend-expand-btn {
background:none; border:none; cursor:pointer;
color:var(--text-muted); font-size:10px; padding:0;
margin-left:6px; touch-action:manipulation;
}
</style>
</head>
<body>
<!-- ===== MAP ===== -->
<div id="map"></div>
<!-- ===== MOBILE SIDEBAR TOGGLE ===== -->
<button class="sidebar-toggle" id="sidebarToggle" onclick="toggleMobileSidebar()" aria-label="Menu">
<i class="fas fa-bars"></i>
</button>
<!-- Sidebar backdrop for mobile -->
<div class="sidebar-backdrop" id="sidebarBackdrop" onclick="closeMobileSidebar()"></div>
<!-- ===== SIDEBAR ===== -->
<div class="sidebar" id="sidebar">
<div class="sidebar-header">
<div class="sidebar-logo"><i class="fas fa-map-marked-alt"></i></div>
<div class="sidebar-title">
<h1>Dashboard</h1>
<p>Poverty Mapping</p>
</div>
<div style="margin-left:auto; display:flex; align-items:center; gap:2px;">
<button class="btn-admin-panel" onclick="openAdminPanel()" style="margin:0;padding:6px 10px;font-size:11px;min-height:36px;">
<i class="fas fa-cog"></i> <span class="hide-xs">Laporan</span>
</button>
<button class="logout-btn" onclick="logout()" title="Logout">
<i class="fas fa-sign-out-alt"></i>
</button>
</div>
</div>
<div class="sidebar-content">
<div class="nav-tabs">
<div class="nav-tab active" data-tab="overview"><i class="fas fa-eye"></i> <span class="tab-label">Ringkasan</span></div>
<div class="nav-tab" data-tab="centers"><i class="fas fa-place-of-worship"></i> <span class="tab-label">Ibadah</span></div>
<div class="nav-tab" data-tab="houses"><i class="fas fa-home"></i> <span class="tab-label">Rumah</span></div>
<div class="nav-tab" data-tab="dashboard"><i class="fas fa-chart-bar"></i> <span class="tab-label">Chart</span></div>
</div>
<div class="stats-grid">
<div class="stat-card purple">
<div class="stat-icon"><i class="fas fa-place-of-worship"></i></div>
<div class="stat-value" id="statCenters">0</div>
<div class="stat-label">Tempat Ibadah</div>
</div>
<div class="stat-card green">
<div class="stat-icon"><i class="fas fa-home"></i></div>
<div class="stat-value" id="statHouses">0</div>
<div class="stat-label">Rumah</div>
</div>
<div class="stat-card orange">
<div class="stat-icon"><i class="fas fa-users"></i></div>
<div class="stat-value" id="statPopulation">0</div>
<div class="stat-label">Tanggungan</div>
</div>
<div class="stat-card teal">
<div class="stat-icon"><i class="fas fa-hand-holding-heart"></i></div>
<div class="stat-value" id="statAided">0</div>
<div class="stat-label">Terima Bantuan</div>
</div>
<div class="stat-card red" id="cardPending">
<div class="stat-icon"><i class="fas fa-flag"></i></div>
<div class="stat-value" id="statPending">0</div>
<div class="stat-label">Laporan Publik</div>
</div>
</div>
<div class="search-box">
<i class="fas fa-search"></i>
<input type="text" id="searchInput" placeholder="Cari nama, alamat, NIK...">
</div>
<div class="filter-section">
<div class="filter-title">Filter Tampilan</div>
<div class="filter-buttons">
<button class="filter-btn active" data-filter="all">Semua</button>
<button class="filter-btn" data-filter="centers">Ibadah</button>
<button class="filter-btn" data-filter="houses">Rumah</button>
</div>
</div>
<div id="dataListsContainer">
<div class="data-section" id="centersListSection">
<div class="section-title">
<span><i class="fas fa-place-of-worship"></i> Tempat Ibadah</span>
<span class="count-badge" id="centerCount">0</span>
</div>
<div class="data-list" id="centersList">
<div class="empty-state"><i class="fas fa-place-of-worship"></i><p>Belum ada data</p></div>
</div>
</div>
<div class="data-section" id="housesListSection">
<div class="section-title">
<span><i class="fas fa-home"></i> Rumah</span>
<span class="count-badge" id="houseCount">0</span>
</div>
<div class="data-list" id="housesList">
<div class="empty-state"><i class="fas fa-home"></i><p>Belum ada data</p></div>
</div>
</div>
</div>
</div>
</div>
<!-- ===== LEGEND (collapsible on mobile) ===== -->
<div class="legend" id="legend">
<h4 onclick="toggleLegend()">
Keterangan
<button class="legend-expand-btn" title="Toggle legend">
<i class="fas fa-chevron-up" id="legendChevron"></i>
</button>
</h4>
<div class="legend-content" id="legendContent">
<div class="legend-section-label">Tempat Ibadah</div>
<div class="legend-item"><div class="legend-icon" style="background:#1d6fa4;"><i class="fas fa-mosque"></i></div><span>Masjid</span></div>
<div class="legend-item"><div class="legend-icon" style="background:#7c3aed;"><i class="fas fa-church"></i></div><span>Gereja</span></div>
<div class="legend-item"><div class="legend-icon" style="background:#b45309;"><i class="fas fa-torii-gate"></i></div><span>Klenteng</span></div>
<div class="legend-item"><div class="legend-icon" style="background:#0e7f6e;"><i class="fas fa-om"></i></div><span>Pura</span></div>
<div class="legend-item"><div class="legend-icon" style="background:#a16207;"><i class="fas fa-dharmachakra"></i></div><span>Vihara</span></div>
<div class="legend-section-label" style="margin-top:8px;">Kategori Kemiskinan</div>
<div class="legend-poverty-item"><div class="legend-poverty-dot" style="background:#d63230;"></div><span>Sangat Miskin</span></div>
<div class="legend-poverty-item"><div class="legend-poverty-dot" style="background:#f76707;"></div><span>Miskin</span></div>
<div class="legend-poverty-item"><div class="legend-poverty-dot" style="background:#f59e0b;"></div><span>Rentan Miskin</span></div>
<div class="legend-poverty-item"><div class="legend-poverty-dot" style="background:#0b9e73;"></div><span>Terdata</span></div>
</div>
</div>
<!-- ===== LAYER CONTROL ===== -->
<div class="custom-layer-control">
<h4><i class="fas fa-layer-group"></i> <span>Layer</span></h4>
<div class="custom-layer-item" onclick="toggleLayer('centers')">
<input type="checkbox" id="layerCenters" checked>
<i class="fas fa-place-of-worship layer-icon layer-icon-center"></i>
<span>Tempat Ibadah</span>
<small id="layerCenterCount">0</small>
</div>
<div class="custom-layer-item" onclick="toggleLayer('houses')">
<input type="checkbox" id="layerHouses" checked>
<i class="fas fa-home layer-icon layer-icon-house"></i>
<span>Rumah</span>
<small id="layerHouseCount">0</small>
</div>
</div>
<!-- ===== LOADING ===== -->
<div class="loading" id="loading"><i class="fas fa-circle-notch fa-spin"></i><span>Memproses...</span></div>
<div class="toast" id="toast"></div>
<button class="help-btn" id="helpBtn" title="Panduan Pengguna"><i class="fas fa-question-circle"></i></button>
<!-- ================================================================
MODAL: Religious Center
================================================================ -->
<div class="modal-overlay" id="centerModal">
<div class="modal">
<div class="modal-header">
<h2 id="centerModalTitle">Tambah Tempat Ibadah</h2>
<span class="modal-close" onclick="closeModal('centerModal')">&times;</span>
</div>
<form id="centerForm" novalidate>
<input type="hidden" id="centerId">
<input type="hidden" id="centerLat">
<input type="hidden" id="centerLng">
<div class="form-group">
<label>Nama *</label>
<input type="text" id="centerName" required placeholder="Contoh: Masjid Al-Ikhlas">
</div>
<div class="form-row">
<div class="form-group">
<label>Jenis Ibadah</label>
<select id="centerWorshipType">
<option value="masjid">Masjid</option><option value="gereja">Gereja</option>
<option value="klenteng">Klenteng</option><option value="pura">Pura</option><option value="vihara">Vihara</option>
</select>
</div>
<div class="form-group">
<label>Radius (m)</label>
<input type="number" id="centerRadius" min="50" max="5000" value="300" step="10">
</div>
</div>
<div class="form-group">
<label>Slider Radius</label>
<div class="slider-container">
<input type="range" id="centerRadiusSlider" min="50" max="5000" value="300" step="10">
<span class="slider-value" id="centerRadiusValue">300m</span>
</div>
</div>
<div class="form-row">
<div class="form-group"><label>Kontak Person</label><input type="text" id="centerContactPerson" placeholder="Nama penanggung jawab"></div>
<div class="form-group"><label>Nomor Telepon</label><input type="text" id="centerContactPhone" placeholder="08xx-xxxx-xxxx"></div>
</div>
<div class="form-group"><label>Catatan</label><textarea id="centerNotes" rows="2" placeholder="Informasi tambahan..."></textarea></div>
<div class="form-group"><label>Alamat</label><input type="text" id="centerAddress" readonly placeholder="Terisi otomatis dari peta"></div>
<div class="form-row">
<div class="form-group"><label>Latitude</label><input type="text" id="centerLatDisplay" readonly></div>
<div class="form-group"><label>Longitude</label><input type="text" id="centerLngDisplay" readonly></div>
</div>
<div class="modal-actions">
<button type="submit" class="btn btn-primary"><i class="fas fa-save"></i> Simpan</button>
<button type="button" class="btn btn-secondary" onclick="closeModal('centerModal')">Batal</button>
</div>
</form>
</div>
</div>
<!-- ================================================================
MODAL: Household
================================================================ -->
<div class="modal-overlay" id="houseModal">
<div class="modal" style="max-width:560px;">
<div class="modal-header">
<h2 id="houseModalTitle">Tambah Rumah Tangga</h2>
<span class="modal-close" onclick="closeModal('houseModal')">&times;</span>
</div>
<form id="houseForm" novalidate>
<input type="hidden" id="houseId">
<input type="hidden" id="houseLat">
<input type="hidden" id="houseLng">
<input type="hidden" id="familyMembersData" value="[]">
<div class="poverty-preview" id="povertyPreview">
<div class="poverty-score-ring" id="povertyRing"><i id="povertyIcon" class="fas fa-circle" style="font-size:16px;"></i></div>
<div style="flex:1;">
<div class="poverty-status-label" id="povertyStatusLabel">Belum dihitung</div>
<div class="poverty-indicators" id="povertyIndicators" style="font-size:9px;color:#5a6478;margin-top:4px;padding-left:0;list-style:none;max-height:70px;overflow-y:auto;"></div>
</div>
</div>
<!-- Alamat -->
<div class="form-section" style="margin-bottom:14px;">
<div class="section-title" style="margin-bottom:8px;">Informasi Alamat</div>
<div class="form-row">
<div class="form-group"><label>RT</label><input type="text" id="houseRt" maxlength="5" placeholder="01"></div>
<div class="form-group"><label>RW</label><input type="text" id="houseRw" maxlength="5" placeholder="02"></div>
</div>
<div class="form-row">
<div class="form-group"><label>Kelurahan</label><input type="text" id="houseKelurahan" readonly></div>
<div class="form-group"><label>Kecamatan</label><input type="text" id="houseKecamatan" readonly></div>
</div>
<div class="form-group"><label>Alamat Lengkap</label><textarea id="houseFullAddress" rows="2" placeholder="Alamat lengkap (dapat diedit manual)" style="background: var(--surface);"></textarea></div>
<div class="form-row">
<div class="form-group"><label>Pusat Pengelola</label><input type="text" id="managingCenterName" readonly placeholder="Otomatis terdeteksi"><input type="hidden" id="managingCenterId"></div>
<div class="form-group"><label>Kondisi Rumah</label><select id="houseCondition"><option value="layak">Layak</option><option value="tidak_layak">Tidak Layak</option></select></div>
</div>
</div>
<!-- Anggota Keluarga -->
<div class="form-section" style="margin-bottom:14px;">
<div class="section-title" style="margin-bottom:8px;">
<span>Anggota Keluarga</span>
<button type="button" class="btn-add-member" onclick="openFamilyMemberModal()"><i class="fas fa-plus"></i> Tambah</button>
</div>
<div id="familyMembersList" class="family-member-list">
<div class="empty-state" style="padding:16px;text-align:center;"><i class="fas fa-users"></i><p>Belum ada anggota keluarga</p></div>
</div>
</div>
<!-- Form tabs -->
<div class="form-tabs">
<button type="button" class="form-tab active" data-ftab="identity">Identitas KK</button>
<button type="button" class="form-tab" data-ftab="economic">Ekonomi</button>
<button type="button" class="form-tab" data-ftab="aid">Bantuan</button>
</div>
<div class="form-tab-panel active" id="ftab-identity">
<div class="form-group"><label>Nama Kepala Keluarga <span style="color:red;">*</span></label><input type="text" id="houseHeadName" required placeholder="Nama lengkap"></div>
<div class="field-error" id="errHouseHeadName" style="display: none; font-size: 11px; color: var(--danger); margin-top: 4px;">
<i class="fas fa-exclamation-circle"></i> Nama Kepala Keluarga wajib diisi.
</div>
<div class="form-row">
<div class="form-group"><label>NIK Kepala Keluarga <span style="color:red;">*</span></label><input type="text" id="houseNIK" maxlength="16" placeholder="16 digit NIK"></div>
<div class="field-error" id="errHouseNIK" style="display: none; font-size: 11px; color: var(--danger); margin-top: 4px;">
<i class="fas fa-exclamation-circle"></i> NIK Kepala Keluarga wajib diisi.
</div>
<div class="form-group"><label>Jenis Kelamin <span style="color:red;">*</span></label><select id="houseGender" required><option value="male">Laki-laki</option><option value="female">Perempuan</option></select></div>
<div class="field-error" id="errHouseGender" style="display: none; font-size: 11px; color: var(--danger); margin-top: 4px;">
<i class="fas fa-exclamation-circle"></i> Jenis Kelamin wajib diisi.
</div>
</div>
<div class="form-row">
<div class="form-group"><label>Tanggal Lahir Kepala Keluarga <span style="color:red;">*</span></label><input type="date" id="houseDOB" required></div>
<div class="field-error" id="errHouseDOB" style="display: none; font-size: 11px; color: var(--danger); margin-top: 4px;">
<i class="fas fa-exclamation-circle"></i> Tanggal Lahir Kepala Keluarga wajib diisi.
</div>
<div class="form-group"><label>Pendidikan Kepala Keluarga <span style="color:red;">*</span></label>
<select id="houseEducation" onchange="recalcPoverty()">
<option value="tidak_sekolah">Tidak Sekolah</option><option value="sd" selected>SD</option><option value="smp">SMP</option>
<option value="sma">SMA</option><option value="diploma">Diploma</option><option value="sarjana">Sarjana</option><option value="pascasarjana">Pascasarjana</option>
</select>
</div>
<div class="field-error" id="errHouseEducation" style="display: none; font-size: 11px; color: var(--danger); margin-top: 4px;">
<i class="fas fa-exclamation-circle"></i> Pendidikan Kepala Keluarga wajib diisi.
</div>
</div>
<div class="form-group">
<label>Status Pekerjaan <span style="color:red;">*</span></label>
<select id="houseEmploymentStatus" onchange="toggleHouseEmploymentFields()">
<option value="unemployed">Tidak Bekerja / Menganggur</option>
<option value="working">Bekerja</option>
<option value="studying">Sekolah / Kuliah</option>
</select>
</div>
<!-- Field untuk bekerja -->
<div class="form-group" id="houseJobGroup" style="display:none;">
<label>Nama Pekerjaan</label>
<input type="text" id="houseJob" placeholder="Contoh: Buruh Harian">
</div>
<!-- Field untuk sekolah -->
<div class="form-group" id="houseInstitutionGroup" style="display:none;">
<label>Nama Sekolah / Universitas</label>
<input type="text" id="houseInstitutionName" placeholder="Contoh: SMA Negeri 1">
</div>
</div>
<div class="form-tab-panel" id="ftab-economic">
<div class="form-group"><label>Pendapatan/Bulan (Rp)</label><input type="number" id="houseIncome" min="0" value="0" onchange="recalcPoverty()"></div>
<div class="form-group"><label>Kepemilikan Lahan</label><select id="houseLandOwnership"><option value="milik">Milik Sendiri</option><option value="sewa">Sewa</option><option value="numpang">Numpang</option><option value="lainnya">Lainnya</option></select></div>
</div>
<div class="form-tab-panel" id="ftab-aid">
<div class="form-group"><label>Status Bantuan</label><select id="houseAidStatus"><option value="not_yet">Belum Terima Bantuan</option><option value="received">Sudah Terima Bantuan</option></select></div>
<div id="aidHistoryPanel" style="margin-top:12px;">
<div class="section-title" style="margin-bottom:8px;">
<span>Riwayat Bantuan</span>
<button type="button" class="btn btn-success btn-sm" id="addAidBtn" style="display:none;padding:5px 9px;font-size:10px;"><i class="fas fa-plus"></i> Catat</button>
</div>
<div id="aidHistoryList"><div class="empty-state" style="padding:14px;"><i class="fas fa-gift"></i><p>Belum ada riwayat bantuan</p></div></div>
</div>
</div>
<div class="form-group"><label>Keterangan</label><textarea id="houseDescription" rows="2" placeholder="Informasi tambahan..."></textarea></div>
<!-- Foto Rumah -->
<div class="form-group">
<label>Foto Rumah <span style="font-weight:400;font-size:10.5px;color:var(--text-muted);">(maks. 5 foto · 5 MB)</span></label>
<div class="photo-upload-zone" id="housePhotoZone" onclick="document.getElementById('housePhotos').click()">
<i class="fas fa-camera puz-icon"></i>
<span class="puz-label">Klik atau seret foto ke sini · JPG / PNG</span>
<input type="file" id="housePhotos" accept=".jpg,.jpeg,.png" multiple>
</div>
<div class="photo-strip" id="housePhotoStrip"></div>
<div class="photo-strip" id="houseSavedPhotoStrip"></div>
<div class="photo-error-msg" id="housePhotoError"></div>
</div>
<div class="form-row">
<div class="form-group"><label>Latitude</label><input type="text" id="houseLatDisplay" readonly></div>
<div class="form-group"><label>Longitude</label><input type="text" id="houseLngDisplay" readonly></div>
</div>
<div class="modal-actions">
<button type="submit" class="btn btn-primary"><i class="fas fa-save"></i> Simpan</button>
<button type="button" class="btn btn-secondary" onclick="closeModal('houseModal')">Batal</button>
</div>
</form>
</div>
</div>
<!-- Modal: Family Member -->
<div class="modal-overlay" id="familyMemberModal">
<div class="modal" style="max-width:500px;">
<div class="modal-header">
<h2 id="familyMemberModalTitle">Tambah Anggota Keluarga</h2>
<span class="modal-close" onclick="closeModal('familyMemberModal')">&times;</span>
</div>
<form id="memberForm" novalidate>
<div class="form-row">
<div class="form-group"><label>Nama Lengkap <span style="color:red;">*</span></label><input type="text" id="memberName" required></div>
<div class="form-group"><label>NIK</label><input type="text" id="memberNik" maxlength="16" placeholder="16 digit NIK"></div>
</div>
<div class="form-row">
<div class="form-group"><label>Jenis Kelamin</label><select id="memberGender"><option value="male">Laki-laki</option><option value="female">Perempuan</option></select></div>
<div class="form-group"><label>Tanggal Lahir</label><input type="date" id="memberDob"></div>
</div>
<div class="form-row">
<div class="form-group"><label>Pendidikan</label><select id="memberEducation">
<option value="tidak_sekolah">Tidak Sekolah</option><option value="sd">SD</option><option value="smp">SMP</option>
<option value="sma">SMA</option><option value="diploma">Diploma</option><option value="sarjana">Sarjana</option><option value="pascasarjana">Pascasarjana</option>
</select></div>
<div class="form-group"><label>Hubungan Keluarga</label><select id="memberRelationship">
<option value="ayah">Ayah</option><option value="ibu">Ibu</option><option value="istri">Istri</option><option value="anak">Anak</option>
<option value="kakek">Kakek</option><option value="nenek">Nenek</option><option value="paman">Paman</option>
<option value="bibi">Bibi</option><option value="sepupu">Sepupu</option><option value="keponakan">Keponakan</option><option value="lainnya">Lainnya</option>
</select></div>
</div>
<div class="form-group"><label>Status Pekerjaan</label>
<select id="memberEmploymentStatus" onchange="toggleMemberEmploymentFields()">
<option value="unemployed">Tidak Bekerja / Menganggur</option>
<option value="studying">Sekolah / Kuliah</option>
<option value="working">Bekerja</option>
</select>
</div>
<div class="form-group" id="memberJobGroup" style="display:none;"><label>Nama Pekerjaan</label><input type="text" id="memberJobName" placeholder="Contoh: Buruh Harian"></div>
<div class="form-group" id="memberInstitutionGroup" style="display:none;"><label>Nama Sekolah / Universitas</label><input type="text" id="memberInstitutionName" placeholder="Contoh: SMA Negeri 1"></div>
<div class="form-group"><label>Perkiraan Pendapatan (Rp)</label><input type="number" id="memberIncome" min="0" value="0"><small style="color:var(--text-muted);">Isi 0 jika tidak bekerja atau masih sekolah</small></div>
<div class="modal-actions">
<button type="button" class="btn btn-primary" onclick="saveFamilyMember()"><i class="fas fa-save"></i> Simpan</button>
<button type="button" class="btn btn-secondary" onclick="closeModal('familyMemberModal')">Batal</button>
</div>
</form>
</div>
</div>
<!-- Modal: Aid Record -->
<div class="modal-overlay" id="aidModal">
<div class="modal" style="max-width:380px;">
<div class="modal-header"><h2>Catat Bantuan</h2><span class="modal-close" onclick="closeModal('aidModal')">&times;</span></div>
<form id="aidForm" novalidate>
<input type="hidden" id="aidHouseholdId">
<div class="form-group"><label>Jenis Bantuan *</label><select id="aidType">
<option value="sembako">Sembako</option><option value="pendanaan">Pendanaan</option><option value="pelatihan">Pelatihan</option>
<option value="sembako_pendanaan">Sembako + Pendanaan</option><option value="sembako_pelatihan">Sembako + Pelatihan</option>
<option value="pendanaan_pelatihan">Pendanaan + Pelatihan</option><option value="lengkap">Lengkap (Semua)</option>
</select></div>
<div class="form-row">
<div class="form-group"><label>Tanggal *</label><input type="date" id="aidDate" required></div>
<div class="form-group"><label>Jumlah (Rp)</label><input type="number" id="aidAmount" min="0" value="0"></div>
</div>
<div class="form-group"><label>Catatan</label><textarea id="aidNotes" rows="2" placeholder="Catatan tambahan..."></textarea></div>
<div class="modal-actions">
<button type="submit" class="btn btn-primary"><i class="fas fa-save"></i> Simpan</button>
<button type="button" class="btn btn-secondary" onclick="closeModal('aidModal')">Batal</button>
</div>
</form>
</div>
</div>
<!-- Modal: Admin Panel -->
<div class="modal-overlay" id="adminModal">
<div class="modal" style="max-width:750px;">
<div class="modal-header">
<h2><i class="fas fa-cog"></i> Laporan Publik</h2>
<span class="modal-close" onclick="closeModal('adminModal')">&times;</span>
</div>
<div class="admin-tabs"><button class="admin-tab active" data-atab="pending"><i class="fas fa-flag"></i> Laporan Publik<span class="pending-badge" id="pendingBadge"></span></button></div>
<div class="admin-tab-panel active" id="atab-pending">
<div class="admin-toolbar">
<select id="pendingStatusFilter" class="admin-search" style="max-width:150px;">
<option value="pending">Menunggu</option>
<option value="approved">Disetujui</option>
<option value="rejected">Ditolak</option>
<option value="">Semua Status</option>
</select>
<button class="btn btn-secondary btn-sm" onclick="loadPendingReports()"><i class="fas fa-sync"></i> Refresh</button>
</div>
<div class="admin-table-wrap">
<table class="admin-table" id="pendingTable">
<thead><tr><th>Waktu</th><th>Nama Warga</th><th>Alamat</th><th>Deskripsi</th><th>Status</th><th>Aksi</th></tr></thead>
<tbody id="pendingTbody"><tr><td colspan="6" class="text-center">Klik Refresh untuk memuat.</td></tr></tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Modal: Approve -->
<div class="modal-overlay" id="approveModal">
<div class="modal" style="max-width:420px;">
<div class="modal-header">
<h2><i class="fas fa-check-circle" style="color:var(--success);"></i> Setujui Laporan</h2>
<span class="modal-close" onclick="closeModal('approveModal')">&times;</span>
</div>
<div id="approveReportPreview" style="background:var(--surface-2);border-radius:var(--r);padding:12px;margin-bottom:14px;font-size:12px;"></div>
<div class="photo-strip" id="approvePhotoPreview" style="margin-top:8px;"></div>
<form id="approveForm" novalidate>
<input type="hidden" id="approveReportId">
<p style="font-size:12px;color:var(--text-secondary);margin-bottom:12px;">Data rumah tangga akan dibuat dengan nilai default. Petugas dapat mengedit lengkap setelah data masuk ke peta.</p>
<div class="form-row">
<div class="form-group"><label>Perkiraan Pendapatan/Bln</label><input type="number" id="approveIncome" min="0" value="0"></div>
<div class="form-group"><label>Jumlah Anggota</label><input type="number" id="approveDependents" min="1" value="1"></div>
</div>
<div class="form-row">
<div class="form-group"><label>Kondisi Rumah</label><select id="approveCondition"><option value="tidak_layak" selected>Tidak Layak</option><option value="layak">Layak</option></select></div>
<div class="form-group"><label>Pendidikan KK</label><select id="approveEducation"><option value="tidak_sekolah">Tidak Sekolah</option><option value="sd" selected>SD</option><option value="smp">SMP</option><option value="sma">SMA</option><option value="sarjana">Sarjana</option></select></div>
</div>
<div class="form-group"><label>Catatan Admin (opsional)</label><textarea id="approveNotes" rows="2" placeholder="Catatan untuk laporan ini..."></textarea></div>
<div class="modal-actions">
<button type="submit" class="btn btn-approve"><i class="fas fa-check"></i> Setujui &amp; Tambah ke Peta</button>
<button type="button" class="btn btn-secondary" onclick="closeModal('approveModal')">Batal</button>
</div>
</form>
</div>
</div>
<!-- Modal: Reject -->
<div class="modal-overlay" id="rejectModal">
<div class="modal" style="max-width:380px;">
<div class="modal-header">
<h2><i class="fas fa-times-circle" style="color:var(--danger);"></i> Tolak Laporan</h2>
<span class="modal-close" onclick="closeModal('rejectModal')">&times;</span>
</div>
<form id="rejectForm" novalidate>
<input type="hidden" id="rejectReportId">
<div class="form-group"><label>Alasan Penolakan (opsional)</label><textarea id="rejectNotes" rows="3" placeholder="Contoh: Data duplikat, alamat tidak valid..."></textarea></div>
<div class="modal-actions">
<button type="submit" class="btn btn-reject"><i class="fas fa-times"></i> Tolak Laporan</button>
<button type="button" class="btn btn-secondary" onclick="closeModal('rejectModal')">Batal</button>
</div>
</form>
</div>
</div>
<!-- Dashboard Modal -->
<div class="modal-overlay" id="dashboardModal">
<div class="modal" style="max-width:820px;max-height:90vh;">
<div class="modal-header">
<h2><i class="fas fa-chart-bar"></i> Dashboard Analitik</h2>
<span class="modal-close" onclick="closeModal('dashboardModal')">&times;</span>
</div>
<div class="dashboard-scroll">
<div class="dashboard-grid" id="dashboardGrid">
<div class="chart-card chart-card-sm"><div class="chart-card-header"><h3><i class="fas fa-chart-pie"></i> Distribusi Kemiskinan</h3></div><div class="chart-canvas-wrap"><canvas id="chartPoverty"></canvas></div></div>
<div class="chart-card chart-card-sm"><div class="chart-card-header"><h3><i class="fas fa-chart-line"></i> Tren Pendataan</h3><span class="chart-card-badge">12 Bulan</span></div><div class="chart-canvas-wrap"><canvas id="chartTrend"></canvas></div></div>
<div class="chart-card chart-card-sm"><div class="chart-card-header"><h3><i class="fas fa-user-clock"></i> Distribusi Usia</h3></div><div class="chart-canvas-wrap"><canvas id="chartAge"></canvas></div></div>
<div class="chart-card chart-card-sm"><div class="chart-card-header"><h3><i class="fas fa-hand-holding-heart"></i> Distribusi Bantuan</h3></div><div class="chart-canvas-wrap"><canvas id="chartAid"></canvas></div></div>
</div>
</div>
</div>
</div>
<!-- Help Modal -->
<div class="modal-overlay" id="helpModal">
<div class="modal" style="max-width:500px;">
<div class="modal-header">
<h2><i class="fas fa-question-circle"></i> Panduan Pengguna</h2>
<span class="modal-close" onclick="closeModal('helpModal')">&times;</span>
</div>
<div class="help-steps" id="helpSteps">
<div class="help-step active" data-step="1"><div class="help-step-icon"><i class="fas fa-map-marked-alt"></i></div><h3>Selamat Datang di WebGIS Admin</h3><p>Halaman admin untuk mengelola data rumah tangga, tempat ibadah, dan memverifikasi laporan dari masyarakat.</p></div>
<div class="help-step" data-step="2"><div class="help-step-icon"><i class="fas fa-place-of-worship"></i></div><h3>Menambah Tempat Ibadah</h3><p>Klik tab <strong>"Ibadah"</strong> di sidebar, lalu klik lokasi pada peta. Form akan muncul untuk mengisi detail.</p></div>
<div class="help-step" data-step="3"><div class="help-step-icon"><i class="fas fa-home"></i></div><h3>Menambah Rumah Tangga</h3><p>Klik tab <strong>"Rumah"</strong>, lalu klik lokasi pada peta. Skor kemiskinan dihitung <em>otomatis</em> berdasarkan data yang diisi.</p></div>
<div class="help-step" data-step="4"><div class="help-step-icon"><i class="fas fa-flag"></i></div><h3>Verifikasi Laporan Publik</h3><p>Klik <strong>Panel Admin → Laporan Publik</strong> untuk melihat laporan dari masyarakat. Setujui untuk langsung menambah data ke peta.</p></div>
<div class="help-step" data-step="5"><div class="help-step-icon"><i class="fas fa-chart-bar"></i></div><h3>Dashboard &amp; Laporan</h3><p>Klik tab <strong>"Chart"</strong> untuk grafik analitik. Marker dapat diseret untuk memindahkan posisi. Radius dapat diubah langsung dari popup.</p></div>
</div>
<div class="help-nav">
<button class="btn btn-secondary btn-sm" id="helpPrev" onclick="helpNav(-1)" disabled>&#8592; Sebelumnya</button>
<span id="helpProgress">1 / 5</span>
<button class="btn btn-primary btn-sm" id="helpNext" onclick="helpNav(1)">Berikutnya &#8594;</button>
</div>
</div>
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script src="assets/js/config.js"></script>
<script src="assets/js/api.js"></script>
<script src="assets/js/auth.js"></script>
<script src="assets/js/map.js"></script>
<script src="assets/js/markers.js"></script>
<script src="assets/js/forms.js"></script>
<script src="assets/js/dashboard.js"></script>
<script src="assets/js/admin.js"></script>
<script src="assets/js/public-reports.js"></script>
<script src="assets/js/photo-upload.js"></script>
<script src="assets/js/app.js"></script>
<script>
'use strict';
// ================================================================
// iOS 100vh fix
// ================================================================
function setVH() {
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
}
setVH();
window.addEventListener('resize', () => {
setVH();
if (typeof MAP !== 'undefined' && MAP) setTimeout(() => MAP.invalidateSize(), 150);
});
window.addEventListener('orientationchange', () => {
setTimeout(() => { setVH(); if (typeof MAP !== 'undefined' && MAP) MAP.invalidateSize(); }, 300);
});
// ================================================================
// Legend Toggle - SATU FUNGSI UNTUK SEMUA (desktop + mobile)
// ================================================================
function toggleLegend() {
const legend = document.getElementById('legend');
const chevron = document.getElementById('legendChevron');
if (!legend) return;
legend.classList.toggle('collapsed');
if (chevron) {
chevron.className = legend.classList.contains('collapsed')
? 'fas fa-chevron-down'
: 'fas fa-chevron-up';
}
}
// Set legend default: collapsed on mobile, EXPANDED on desktop
document.addEventListener('DOMContentLoaded', function() {
const legend = document.getElementById('legend');
if (legend) {
if (window.innerWidth <= 768) {
legend.classList.add('collapsed'); // mobile: collapsed
} else {
legend.classList.remove('collapsed'); // desktop: expanded
}
}
});
// ================================================================
// Mobile sidebar toggle
// ================================================================
function toggleMobileSidebar() {
const sidebar = document.getElementById('sidebar');
const backdrop = document.getElementById('sidebarBackdrop');
const isOpen = sidebar.classList.contains('mobile-open');
if (isOpen) {
closeMobileSidebar();
} else {
sidebar.classList.add('mobile-open');
backdrop.classList.add('active');
document.body.style.overflow = 'hidden';
}
}
function closeMobileSidebar() {
const sidebar = document.getElementById('sidebar');
const backdrop = document.getElementById('sidebarBackdrop');
sidebar.classList.remove('mobile-open');
backdrop.classList.remove('active');
document.body.style.overflow = '';
}
// Close sidebar on nav/data-item click (mobile)
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.nav-tab').forEach(tab => {
tab.addEventListener('click', () => {
if (window.innerWidth <= 768) setTimeout(closeMobileSidebar, 120);
});
});
const sidebar = document.getElementById('sidebar');
if (sidebar) {
sidebar.addEventListener('click', (e) => {
if (e.target.closest('.data-item') && window.innerWidth <= 768) setTimeout(closeMobileSidebar, 80);
});
}
const backdrop = document.getElementById('sidebarBackdrop');
if (backdrop) backdrop.addEventListener('click', closeMobileSidebar);
});
// Override closeModal to refresh Leaflet map
const _origCloseModal = window.closeModal;
if (typeof _origCloseModal === 'function') {
window.closeModal = function(id) {
_origCloseModal(id);
if (id === 'dashboardModal' && typeof MAP !== 'undefined' && MAP) {
setTimeout(() => MAP.invalidateSize(), 100);
}
};
}
</script>
</body>
</html>