feat: complete WebGIS implementation with nominal bantuan and cache busting
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
// ================================================================
|
||||
// Auth Helper
|
||||
// ================================================================
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_name(SESSION_NAME);
|
||||
session_start();
|
||||
}
|
||||
|
||||
function isLoggedIn(): bool {
|
||||
return isset($_SESSION['user_id']) && !empty($_SESSION['user_id']);
|
||||
}
|
||||
|
||||
function requireLogin(): void {
|
||||
if (!isLoggedIn()) {
|
||||
header('Location: ' . BASE_URL . '/admin/login.php');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
function requireAdmin(): void {
|
||||
requireLogin();
|
||||
if (getCurrentUser()['role'] !== 'admin') {
|
||||
http_response_code(403);
|
||||
die('<h2>Akses Ditolak</h2><p>Anda tidak memiliki izin untuk mengakses halaman ini.</p>');
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentUser(): ?array {
|
||||
if (!isLoggedIn()) return null;
|
||||
return [
|
||||
'id' => $_SESSION['user_id'],
|
||||
'nama' => $_SESSION['user_nama'] ?? '',
|
||||
'email' => $_SESSION['user_email'] ?? '',
|
||||
'role' => $_SESSION['user_role'] ?? 'operator',
|
||||
];
|
||||
}
|
||||
|
||||
function loginUser(array $user): void {
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['user_nama'] = $user['nama'];
|
||||
$_SESSION['user_email'] = $user['email'];
|
||||
$_SESSION['user_role'] = $user['role'];
|
||||
// Also store as array for API compatibility
|
||||
$_SESSION['user'] = [
|
||||
'id' => $user['id'],
|
||||
'nama' => $user['nama'],
|
||||
'email' => $user['email'],
|
||||
'role' => $user['role'],
|
||||
];
|
||||
}
|
||||
|
||||
function logoutUser(): void {
|
||||
$_SESSION = [];
|
||||
if (ini_get('session.use_cookies')) {
|
||||
$p = session_get_cookie_params();
|
||||
setcookie(session_name(), '', time() - 42000, $p['path'], $p['domain'], $p['secure'], $p['httponly']);
|
||||
}
|
||||
session_destroy();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
</main>
|
||||
</div><!-- .admin-layout -->
|
||||
<?= $extraFooter ?? '' ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
// ================================================================
|
||||
// Helper Functions
|
||||
// ================================================================
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
|
||||
/**
|
||||
* JSON response helper
|
||||
*/
|
||||
function jsonResponse(array $data, int $code = 200): void {
|
||||
http_response_code($code);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Haversine formula: jarak antara dua koordinat (meter)
|
||||
*/
|
||||
function haversineDistance(float $lat1, float $lng1, float $lat2, float $lng2): float {
|
||||
$R = 6371000; // radius bumi meter
|
||||
$dLat = deg2rad($lat2 - $lat1);
|
||||
$dLng = deg2rad($lng2 - $lng1);
|
||||
$a = sin($dLat / 2) * sin($dLat / 2)
|
||||
+ cos(deg2rad($lat1)) * cos(deg2rad($lat2))
|
||||
* sin($dLng / 2) * sin($dLng / 2);
|
||||
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
|
||||
return $R * $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cari rumah ibadah terdekat dari koordinat
|
||||
*/
|
||||
function findNearestIbadah(float $lat, float $lng): ?array {
|
||||
$db = getDB();
|
||||
$rows = $db->query("SELECT id, nama, jenis, lat, lng, radius FROM rumah_ibadah")->fetchAll();
|
||||
$best = null;
|
||||
$minDist = PHP_FLOAT_MAX;
|
||||
foreach ($rows as $row) {
|
||||
$dist = haversineDistance($lat, $lng, (float)$row['lat'], (float)$row['lng']);
|
||||
if ($dist <= (float)$row['radius'] && $dist < $minDist) {
|
||||
$minDist = $dist;
|
||||
$best = array_merge($row, ['jarak' => round($dist, 2)]);
|
||||
}
|
||||
}
|
||||
// Jika tidak ada dalam radius, cari yang paling dekat saja
|
||||
if ($best === null && !empty($rows)) {
|
||||
foreach ($rows as $row) {
|
||||
$dist = haversineDistance($lat, $lng, (float)$row['lat'], (float)$row['lng']);
|
||||
if ($dist < $minDist) {
|
||||
$minDist = $dist;
|
||||
$best = array_merge($row, ['jarak' => round($dist, 2), 'di_luar_radius' => true]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $best;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize string input
|
||||
*/
|
||||
function sanitize(string $val): string {
|
||||
return trim(htmlspecialchars($val, ENT_QUOTES, 'UTF-8'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Format radius display
|
||||
*/
|
||||
function formatRadius(int $meter): string {
|
||||
return $meter >= 1000 ? number_format($meter / 1000, 1) . ' km' : $meter . ' m';
|
||||
}
|
||||
|
||||
/**
|
||||
* Format tanggal Indonesia
|
||||
*/
|
||||
function formatTanggal(?string $date): string {
|
||||
if (!$date) return '-';
|
||||
$ts = strtotime($date);
|
||||
$bulan = ['','Jan','Feb','Mar','Apr','Mei','Jun','Jul','Agt','Sep','Okt','Nov','Des'];
|
||||
return date('d', $ts) . ' ' . $bulan[(int)date('n', $ts)] . ' ' . date('Y', $ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle file upload
|
||||
*/
|
||||
function handleUpload(array $file, string $prefix = 'bukti'): ?string {
|
||||
if ($file['error'] !== UPLOAD_ERR_OK) return null;
|
||||
if ($file['size'] > UPLOAD_MAX_SIZE) return null;
|
||||
|
||||
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
||||
if (!in_array($ext, UPLOAD_ALLOWED)) return null;
|
||||
|
||||
if (!is_dir(UPLOAD_DIR)) mkdir(UPLOAD_DIR, 0755, true);
|
||||
|
||||
$filename = $prefix . '_' . date('Ymd_His') . '_' . uniqid() . '.' . $ext;
|
||||
$dest = UPLOAD_DIR . $filename;
|
||||
if (move_uploaded_file($file['tmp_name'], $dest)) return $filename;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emoji dan label untuk jenis ibadah
|
||||
*/
|
||||
function ibadahEmoji(string $jenis): string {
|
||||
$map = [
|
||||
'Masjid' => '🕌',
|
||||
'Musholla' => '🕌',
|
||||
'Gereja' => '⛪',
|
||||
'Katolik' => '⛪',
|
||||
'Pura' => '🛕',
|
||||
'Vihara' => '🛕',
|
||||
'Klenteng' => '⛩️',
|
||||
'Lainnya' => '🙏',
|
||||
];
|
||||
return $map[$jenis] ?? '🏛️';
|
||||
}
|
||||
|
||||
/**
|
||||
* Color untuk marker berdasarkan status
|
||||
*/
|
||||
function statusColor(string $status): string {
|
||||
return match($status) {
|
||||
'sudah' => '#22c55e',
|
||||
'menunggu' => '#f59e0b',
|
||||
default => '#ef4444',
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/config.php';
|
||||
require_once __DIR__ . '/auth.php';
|
||||
$user = getCurrentUser();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= isset($pageTitle) ? htmlspecialchars($pageTitle) . ' — ' : '' ?><?= APP_NAME ?></title>
|
||||
<meta name="description" content="WebGIS Sebaran Penduduk Miskin — Sistem pemetaan interaktif rumah ibadah dan penduduk miskin berbasis web.">
|
||||
<!-- Bootstrap 5 CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
|
||||
<!-- Google Fonts -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<!-- SweetAlert2 CSS -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
||||
<!-- Admin CSS -->
|
||||
<link rel="stylesheet" href="<?= BASE_URL ?>/assets/css/admin.css?v=<?= time() ?>">
|
||||
<?= $extraHead ?? '' ?>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Bootstrap 5 JS (di head agar tersedia untuk modal) -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- SweetAlert2 JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
|
||||
<!-- ══ NAVBAR ══════════════════════════════════════════════ -->
|
||||
<nav class="admin-navbar">
|
||||
<a href="<?= BASE_URL ?>/admin/" class="navbar-brand">
|
||||
<span class="brand-icon">🗺️</span>
|
||||
<span><?= APP_NAME ?></span>
|
||||
</a>
|
||||
<div class="navbar-right">
|
||||
<a href="<?= BASE_URL ?>/" target="_blank" class="btn-nav-link" title="Lihat Peta">
|
||||
<i class="bi bi-map"></i> Buka Peta
|
||||
</a>
|
||||
<?php if ($user): ?>
|
||||
<div class="user-badge">
|
||||
<span class="user-role-dot <?= $user['role'] ?>"></span>
|
||||
<span><?= htmlspecialchars($user['nama']) ?></span>
|
||||
<span class="role-pill"><?= ucfirst($user['role']) ?></span>
|
||||
</div>
|
||||
<a href="<?= BASE_URL ?>/admin/logout.php" class="btn-nav-link danger" title="Logout">
|
||||
<i class="bi bi-box-arrow-right"></i>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="admin-layout">
|
||||
<!-- ══ SIDEBAR ══════════════════════════════════════════════ -->
|
||||
<aside class="admin-sidebar" id="admin-sidebar">
|
||||
<nav class="sidebar-nav">
|
||||
<div class="nav-section-label">Menu</div>
|
||||
<a href="<?= BASE_URL ?>/admin/" class="nav-item <?= (basename($_SERVER['PHP_SELF']) === 'index.php' && strpos($_SERVER['REQUEST_URI'], '/admin/') !== false) ? 'active' : '' ?>">
|
||||
<i class="bi bi-speedometer2"></i> Dashboard
|
||||
</a>
|
||||
<a href="<?= BASE_URL ?>/admin/rumah_ibadah.php" class="nav-item <?= (basename($_SERVER['PHP_SELF']) === 'rumah_ibadah.php') ? 'active' : '' ?>">
|
||||
<i class="bi bi-building"></i> Rumah Ibadah
|
||||
</a>
|
||||
<a href="<?= BASE_URL ?>/admin/penduduk_miskin.php" class="nav-item <?= (basename($_SERVER['PHP_SELF']) === 'penduduk_miskin.php') ? 'active' : '' ?>">
|
||||
<i class="bi bi-people"></i> Penduduk Miskin
|
||||
</a>
|
||||
|
||||
<?php if ($user && $user['role'] === 'admin'): ?>
|
||||
<div class="nav-section-label" style="margin-top:20px;">Admin</div>
|
||||
<a href="<?= BASE_URL ?>/admin/import.php" class="nav-item <?= (basename($_SERVER['PHP_SELF']) === 'import.php') ? 'active' : '' ?>">
|
||||
<i class="bi bi-upload"></i> Import Data
|
||||
</a>
|
||||
<a href="<?= BASE_URL ?>/admin/export.php" class="nav-item <?= (basename($_SERVER['PHP_SELF']) === 'export.php') ? 'active' : '' ?>">
|
||||
<i class="bi bi-download"></i> Export Data
|
||||
</a>
|
||||
<a href="<?= BASE_URL ?>/admin/users.php" class="nav-item <?= (basename($_SERVER['PHP_SELF']) === 'users.php') ? 'active' : '' ?>">
|
||||
<i class="bi bi-person-gear"></i> Pengguna
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="nav-section-label" style="margin-top:20px;">Lainnya</div>
|
||||
<a href="<?= BASE_URL ?>/" target="_blank" class="nav-item">
|
||||
<i class="bi bi-map-fill"></i> Lihat Peta
|
||||
</a>
|
||||
<a href="<?= BASE_URL ?>/admin/logout.php" class="nav-item danger">
|
||||
<i class="bi bi-box-arrow-right"></i> Logout
|
||||
</a>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<!-- ══ MAIN CONTENT ══════════════════════════════════════════ -->
|
||||
<main class="admin-content">
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php // Modal: Tambah / Edit Rumah Ibadah ?>
|
||||
|
||||
<div class="modal-overlay" id="modal-ibadah">
|
||||
<div class="modal-card">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="modal-header" style="background:linear-gradient(135deg,rgba(91,127,255,0.12),rgba(124,91,255,0.08));border-bottom:1px solid rgba(91,127,255,0.2);">
|
||||
<div class="modal-title" id="modal-ibadah-title">🏛️ Tambah Rumah Ibadah</div>
|
||||
<button class="modal-close" onclick="closeModalIbadah()" type="button" title="Tutup">✕</button>
|
||||
</div>
|
||||
|
||||
<!-- Body -->
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="ibadah-edit-id">
|
||||
|
||||
<!-- Lokasi -->
|
||||
<div class="section-label">📍 Lokasi</div>
|
||||
<div class="form-group">
|
||||
<div class="addr-preview" id="ibadah-coord-display" style="font-family:monospace;font-size:11px;">Lat: — Lng: —</div>
|
||||
<div class="addr-preview" id="ibadah-addr-display" style="margin-top:6px;">
|
||||
<span class="addr-loading">Pilih titik di peta terlebih dahulu...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Kelurahan</label>
|
||||
<input class="form-control" id="ibadah-kelurahan" placeholder="Kelurahan / Desa">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Kecamatan</label>
|
||||
<input class="form-control" id="ibadah-kecamatan" placeholder="Kecamatan">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Rumah Ibadah -->
|
||||
<div class="section-label">🕌 Data Rumah Ibadah</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Nama Rumah Ibadah <span style="color:var(--red)">*</span></label>
|
||||
<input class="form-control" id="ibadah-nama" placeholder="Mis. Masjid Al-Ikhlas">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Jenis <span style="color:var(--red)">*</span></label>
|
||||
<select class="form-control" id="ibadah-jenis">
|
||||
<option value="Masjid">🕌 Masjid</option>
|
||||
<option value="Musholla">🕌 Musholla</option>
|
||||
<option value="Gereja">⛪ Gereja</option>
|
||||
<option value="Katolik">⛪ Gereja Katolik</option>
|
||||
<option value="Pura">🛕 Pura</option>
|
||||
<option value="Vihara">🛕 Vihara</option>
|
||||
<option value="Klenteng">⛩️ Klenteng</option>
|
||||
<option value="Lainnya">🙏 Lainnya</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Kontak / Telepon</label>
|
||||
<input class="form-control" id="ibadah-kontak" placeholder="0561-xxx / 08xx-xxxx">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Radius -->
|
||||
<div class="section-label">📏 Radius Layanan</div>
|
||||
<div class="form-group">
|
||||
<div class="range-wrapper">
|
||||
<input type="range" id="ibadah-radius" min="100" max="5000" step="50" value="300"
|
||||
style="flex:1;accent-color:var(--accent);">
|
||||
<span class="range-val" id="ibadah-radius-val">300 m</span>
|
||||
</div>
|
||||
<div style="display:flex;justify-content:space-between;font-size:9px;color:var(--text3);margin-top:3px;">
|
||||
<span>Min: 100 m</span><span>Default: 300 m</span><span>Max: 5 km</span>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.modal-body -->
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-ghost" onclick="closeModalIbadah()" type="button">
|
||||
<i class="bi bi-x-lg"></i> Batal
|
||||
</button>
|
||||
<button class="btn btn-primary" id="btn-save-ibadah" type="button">
|
||||
<i class="bi bi-floppy2-fill"></i> Simpan
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-card -->
|
||||
</div><!-- /.modal-overlay #modal-ibadah -->
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php // Modal: Tambah / Edit Penduduk Miskin ?>
|
||||
|
||||
<div class="modal-overlay" id="modal-miskin">
|
||||
<div class="modal-card" style="max-width:600px;">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="modal-header" style="background:linear-gradient(135deg,rgba(34,197,94,0.1),rgba(34,197,94,0.04));border-bottom:1px solid rgba(34,197,94,0.2);">
|
||||
<div class="modal-title" id="modal-miskin-title">👤 Tambah Penduduk Miskin</div>
|
||||
<button class="modal-close" onclick="closeModalMiskin()" type="button" title="Tutup">✕</button>
|
||||
</div>
|
||||
|
||||
<!-- Body -->
|
||||
<div class="modal-body">
|
||||
<input type="hidden" id="miskin-edit-id">
|
||||
|
||||
<!-- Lokasi -->
|
||||
<div class="section-label">📍 Lokasi</div>
|
||||
<div class="form-group">
|
||||
<div class="addr-preview" id="miskin-coord-display" style="font-family:monospace;font-size:11px;">Lat: — Lng: —</div>
|
||||
<div class="addr-preview" id="miskin-addr-display" style="margin-top:6px;">
|
||||
<span class="addr-loading">Pilih titik di peta terlebih dahulu...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Kelurahan</label>
|
||||
<input class="form-control" id="miskin-kelurahan" placeholder="Kelurahan / Desa">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Kecamatan</label>
|
||||
<input class="form-control" id="miskin-kecamatan" placeholder="Kecamatan">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Data Keluarga -->
|
||||
<div class="section-label">👨👩👧 Data Kepala Keluarga</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Nama Kepala Keluarga <span style="color:var(--red)">*</span></label>
|
||||
<input class="form-control" id="miskin-kk-nama" placeholder="Nama lengkap kepala keluarga">
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">NIK KK</label>
|
||||
<input class="form-control" id="miskin-nik" placeholder="16 digit NIK (opsional)" maxlength="16">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Jumlah Anggota</label>
|
||||
<input class="form-control" id="miskin-jumlah" type="number" min="1" max="30" value="1" placeholder="1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Anggota Keluarga -->
|
||||
<div class="section-label">👥 Detail Anggota Keluarga</div>
|
||||
<div id="anggota-container"></div>
|
||||
<button class="btn btn-outline-accent" id="btn-add-anggota" type="button"
|
||||
style="width:100%;margin-bottom:4px;">
|
||||
<i class="bi bi-plus-circle"></i> Tambah Anggota Keluarga
|
||||
</button>
|
||||
|
||||
<!-- Status Bantuan -->
|
||||
<div class="section-label">🤝 Status Bantuan</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Status Bantuan <span style="color:var(--red)">*</span></label>
|
||||
<select class="form-control" id="miskin-status">
|
||||
<option value="belum">❌ Belum Dibantu</option>
|
||||
<option value="menunggu">⏳ Menunggu Verifikasi</option>
|
||||
<option value="sudah">✅ Sudah Dibantu</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Bantuan fields (tampil untuk: sudah DAN menunggu) -->
|
||||
<div id="bantuan-fields" style="display:none;">
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Jenis Bantuan</label>
|
||||
<input class="form-control" id="miskin-jenis-bantuan" placeholder="Mis. Sembako + Uang Tunai">
|
||||
</div>
|
||||
<div class="form-group" id="wrap-tanggal">
|
||||
<label class="form-label">Tanggal Bantuan</label>
|
||||
<input class="form-control" id="miskin-tanggal" type="date">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- BARU: Nominal Bantuan (Rupiah) -->
|
||||
<div class="form-group">
|
||||
<label class="form-label">💰 Nominal Bantuan (Rupiah)</label>
|
||||
<div style="position:relative;">
|
||||
<span style="position:absolute;left:12px;top:50%;transform:translateY(-50%);font-size:12px;color:var(--text2);font-weight:700;pointer-events:none;">Rp</span>
|
||||
<input class="form-control" id="miskin-nominal"
|
||||
type="text" inputmode="numeric"
|
||||
placeholder="0"
|
||||
style="padding-left:36px;font-family:'JetBrains Mono',monospace;"
|
||||
oninput="formatNominalInput(this)">
|
||||
</div>
|
||||
<div style="font-size:10px;color:var(--text3);margin-top:4px;">Kosongkan jika belum ditentukan nominal</div>
|
||||
</div>
|
||||
|
||||
<!-- Keterangan (tampil khusus status menunggu) -->
|
||||
<div class="form-group" id="keterangan-menunggu-wrap" style="display:none;">
|
||||
<label class="form-label">📋 Keterangan Verifikasi</label>
|
||||
<input class="form-control" id="miskin-keterangan" placeholder="Alasan atau catatan menunggu verifikasi...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload Bukti -->
|
||||
<div class="section-label">📎 Bukti Pendukung (Opsional)</div>
|
||||
<div class="form-group">
|
||||
<label class="upload-area" for="miskin-bukti" id="upload-area-miskin">
|
||||
<input type="file" id="miskin-bukti" accept=".jpg,.jpeg,.png,.gif,.pdf,.doc,.docx" style="position:absolute;inset:0;opacity:0;cursor:pointer;">
|
||||
<div class="upload-text">
|
||||
<div style="font-size:22px;margin-bottom:4px;">📁</div>
|
||||
<div>Klik atau seret file ke sini</div>
|
||||
<div style="font-size:10px;color:var(--text3);margin-top:3px;">JPG · PNG · PDF · DOC (maks 10 MB)</div>
|
||||
</div>
|
||||
</label>
|
||||
<div id="miskin-bukti-preview"></div>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-body -->
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-ghost" onclick="closeModalMiskin()" type="button">
|
||||
<i class="bi bi-x-lg"></i> Batal
|
||||
</button>
|
||||
<button class="btn btn-success" id="btn-save-miskin" type="button">
|
||||
<i class="bi bi-floppy2-fill"></i> Simpan
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div><!-- /.modal-card -->
|
||||
</div><!-- /.modal-overlay #modal-miskin -->
|
||||
Reference in New Issue
Block a user