'success', 'message' => 'Foto berhasil diperbarui']); } else { echo json_encode(['status' => 'error', 'message' => 'Gagal menulis file ke hosting. Pastikan permission folder assets/photo adalah 0755 atau 0777.']); } } else { echo json_encode(['status' => 'error', 'message' => 'Data tidak lengkap']); } exit; } // ================================================================= // 1. FUNGSI FETCH DATA (Anti-Cache) // ================================================================= function getSheetData($url, $sheetName) { $finalUrl = $url . "?sheet=" . urlencode($sheetName) . "&t=" . time(); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $finalUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $res = curl_exec($ch); curl_close($ch); if (!$res) $res = @file_get_contents($finalUrl); return json_decode($res, true) ?: []; } $peserta_raw = getSheetData($api_url, "peserta"); $event_raw = getSheetData($api_url, "Event"); $header = []; if (!empty($peserta_raw) && is_array($peserta_raw)) { $header = array_shift($peserta_raw); } // ================================================================= // 2. IDENTIFIKASI INDEX KOLOM // ================================================================= $idx_nama = -1; $idx_kab = -1; $idx_kec = -1; $idx_pek = -1; $idx_tgl = -1; $idx_gender = -1; $idx_lahir = -1; $idx_hp = -1; $idx_agama = -1; foreach ($header as $i => $h) { $hl = strtolower(trim($h)); if (strpos($hl, 'nama') !== false) $idx_nama = $i; if (strpos($hl, 'kabupaten') !== false) $idx_kab = $i; if (strpos($hl, 'kecamatan') !== false || strpos($hl, 'area') !== false) $idx_kec = $i; if (strpos($hl, 'pekerjaan') !== false) $idx_pek = $i; if (strpos($hl, 'gabung') !== false || strpos($hl, 'timestamp') !== false) $idx_tgl = $i; if (strpos($hl, 'gender') !== false || strpos($hl, 'kelamin') !== false) $idx_gender = $i; if (strpos($hl, 'lahir') !== false && strpos($hl, 'tanggal') !== false) $idx_lahir = $i; if (strpos($hl, 'hp') !== false || strpos($hl, 'whatsapp') !== false) $idx_hp = $i; if (strpos($hl, 'agama') !== false) $idx_agama = $i; } // ================================================================= // 3. PEMROSESAN DATA // ================================================================= $current_year = (int)date('Y'); $today_ts = strtotime(date('Y-m-d')); $valid_peserta = []; $filters = ['kab' => [], 'kec' => [], 'pek' => [], 'tgl' => []]; $dash_gender = ['Laki-Laki' => 0, 'Perempuan' => 0]; $dash_area = []; foreach ($peserta_raw as &$row) { if (empty(array_filter($row))) continue; foreach ($row as $ci => &$cell) { if (is_string($cell) && preg_match('/^(\d{4}-\d{2}-\d{2})T\d{2}:\d{2}:\d{2}/', $cell, $matches)) { $cell = date('d/m/Y', strtotime($matches[1])); } } unset($cell); if ($idx_kab !== -1 && !empty($row[$idx_kab])) $filters['kab'][$row[$idx_kab]] = true; if ($idx_kec !== -1 && !empty($row[$idx_kec])) $filters['kec'][$row[$idx_kec]] = true; if ($idx_pek !== -1 && !empty($row[$idx_pek])) $filters['pek'][$row[$idx_pek]] = true; if ($idx_tgl !== -1 && !empty($row[$idx_tgl])) { $tgl_val = explode(' ', trim($row[$idx_tgl]))[0]; $filters['tgl'][$tgl_val] = true; } $usia = null; $days_to_bday = 9999; if ($idx_lahir !== -1 && !empty($row[$idx_lahir])) { $t_lhr = $row[$idx_lahir]; $tgl_bersih = ''; if (preg_match('/^(\d{2})\/(\d{2})\/(\d{4})/', $t_lhr, $m)) $tgl_bersih = "{$m[3]}-{$m[2]}-{$m[1]}"; if ($tgl_bersih) { $time = strtotime($tgl_bersih); $usia = $current_year - (int)date('Y', $time); $next_bday = mktime(0, 0, 0, (int)date('m', $time), (int)date('d', $time), $current_year); if ($next_bday < $today_ts) $next_bday = mktime(0, 0, 0, (int)date('m', $time), (int)date('d', $time), $current_year + 1); $days_to_bday = (int)round(($next_bday - $today_ts) / 86400); } } $nama_p = $idx_nama !== -1 ? trim($row[$idx_nama]) : '-'; $g = $idx_gender !== -1 ? strtolower(trim($row[$idx_gender])) : ''; if (strpos($g, 'l') === 0) $dash_gender['Laki-Laki']++; elseif (strpos($g, 'p') === 0) $dash_gender['Perempuan']++; $kec_p = $idx_kec !== -1 ? trim($row[$idx_kec]) : ''; if ($kec_p) $dash_area[$kec_p] = isset($dash_area[$kec_p]) ? $dash_area[$kec_p] + 1 : 1; // Persiapkan Data Profil Lengkap untuk Modal $valid_peserta[] = [ 'raw' => $row, 'nama' => $nama_p, 'usia' => $usia, 'days_to_bday' => $days_to_bday, 'area' => $kec_p, 'pekerjaan' => $idx_pek !== -1 ? trim($row[$idx_pek]) : '-', 'hp' => $idx_hp !== -1 ? trim($row[$idx_hp]) : '', 'agama' => $idx_agama !== -1 ? trim($row[$idx_agama]) : '-', 'gender_text' => $idx_gender !== -1 ? trim($row[$idx_gender]) : '-', 'tgl_gabung' => $idx_tgl !== -1 ? trim($row[$idx_tgl]) : '-' ]; } unset($row); ksort($filters['kab']); ksort($filters['kec']); ksort($filters['pek']); ksort($filters['tgl']); arsort($dash_area); $dash_area = array_slice($dash_area, 0, 5); // ================================================================= // 4. SORTING DASHBOARD // ================================================================= $peserta_with_age = array_filter($valid_peserta, function($p) { return $p['usia'] !== null; }); usort($peserta_with_age, function($a, $b) { return $b['usia'] <=> $a['usia']; }); $top_5_tertua = array_slice($peserta_with_age, 0, 5); $top_5_termuda = array_slice(array_reverse($peserta_with_age), 0, 5); usort($peserta_with_age, function($a, $b) { return $a['days_to_bday'] <=> $b['days_to_bday']; }); $top_5_ultah = array_slice($peserta_with_age, 0, 5); $random_20 = $valid_peserta; shuffle($random_20); $random_20 = array_slice($random_20, 0, 20); // ================================================================= // 5. EVENT MENDATANG // ================================================================= $upcoming_events = []; if (!empty($event_raw)) { $ev_header = array_shift($event_raw); foreach ($event_raw as $ev) { if (empty(array_filter($ev))) continue; $t_ev = isset($ev[3]) ? $ev[3] : ''; if (preg_match('/^(\d{4}-\d{2}-\d{2})T/', $t_ev, $m)) $t_ev = $m[1]; $ev_ts = strtotime($t_ev); if ($ev_ts >= $today_ts) { $upcoming_events[] = ['nama' => isset($ev[1]) ? $ev[1] : 'Tanpa Nama', 'tgl' => date('d M Y', $ev_ts), 'ts' => $ev_ts]; } } usort($upcoming_events, function($a, $b) { return $a['ts'] <=> $b['ts']; }); $upcoming_events = array_slice($upcoming_events, 0, 5); } // Helper UI function getAgamaBadge($agama) { $u = strtoupper(trim($agama)); if (strpos($u, 'ISLAM') !== false) return 'badge-islam'; if (strpos($u, 'KRISTEN') !== false || strpos($u, 'PROTESTAN') !== false) return 'badge-kristen'; if (strpos($u, 'KATOLIK') !== false) return 'badge-katolik'; if (strpos($u, 'HINDU') !== false) return 'badge-hindu'; if (strpos($u, 'BUDDHA') !== false || strpos($u, 'BUDHA') !== false) return 'badge-buddha'; return 'badge-default'; } function getGenderIcon($gender) { $l = strtolower(trim($gender)); if (in_array($l, ['laki-laki', 'l', 'male', 'pria'])) return ''; if (in_array($l, ['perempuan', 'p', 'female', 'wanita'])) return ''; return ''; } ?> Data Peserta & Dashboard SSDG
Total Peserta
Laki / Perempuan
/
Area Tercover
Event Aktif

Distribusi Gender

Top 5 Area

5 Tertua

Thn

5 Termuda

Thn

Ultah Terdekat

Ke-
$colName): ?>
#
Tidak ada data

Pesanan

Tools Data

Pengaturan Tema

Dark Emerald
Hitam & Hijau Emerald
Ocean Night
Biru Laut & Cyan
Warm Sunset
Terang & Oranye
Clean Light
Putih Bersih & Biru
Neon Cyber
Gelap & Pink Neon