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
@@ -0,0 +1,123 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\PenerimaBantuan;
use App\Models\TempatIbadah;
use App\Models\LogDistribusi;
class KonfirmasiController extends Controller
{
public function show(Request $request)
{
$id = $request->query('id', 0);
$periode_param = $request->query('periode', '');
$signature_param = $request->query('signature', '');
if ($id <= 0 || empty($signature_param) || empty($periode_param)) {
abort(400, 'Permintaan tidak valid. Parameter periode atau signature hilang.');
}
// Verifikasi Signature dengan periode
$expected_signature = hash_hmac('sha256', $id . '|' . $periode_param, config('app.key'));
if (!hash_equals($expected_signature, $signature_param)) {
abort(403, 'Invalid Signature. URL telah dimodifikasi atau tidak sah.');
}
// Validasi Periode Kupon
if ($periode_param !== now()->format('Y-m')) {
$namaBulan = \Carbon\Carbon::createFromFormat('Y-m', $periode_param)->translatedFormat('F Y');
return response("Kupon ini hanya berlaku untuk periode {$namaBulan}. Saat ini adalah periode " . now()->translatedFormat('F Y') . ". Silakan perbarui kupon Anda.", 400);
}
$warga = PenerimaBantuan::findOrFail($id);
if (empty($warga->id_tempat_ibadah)) {
return response('Warga ini belum terdaftar di tempat ibadah manapun untuk pengambilan bantuan.', 400);
}
$id_tempat = $warga->id_tempat_ibadah;
// Cek apakah sudah pernah dicairkan bulan ini
$log = LogDistribusi::where('id_penerima', $id)
->whereMonth('tanggal_diterima', now()->month)
->whereYear('tanggal_diterima', now()->year)
->orderBy('tanggal_diterima', 'desc')
->first();
$sudah_cair = ($log !== null);
return view('konfirmasi', compact('warga', 'id_tempat', 'sudah_cair', 'log'));
}
public function process(Request $request)
{
$id = $request->query('id', 0);
$periode_param = $request->query('periode', '');
$signature_param = $request->query('signature', '');
if ($id <= 0 || empty($signature_param) || empty($periode_param)) {
abort(400, 'Permintaan tidak valid. Parameter periode atau signature hilang.');
}
// Verifikasi Signature dengan periode
$expected_signature = hash_hmac('sha256', $id . '|' . $periode_param, config('app.key'));
if (!hash_equals($expected_signature, $signature_param)) {
abort(403, 'Invalid Signature.');
}
// Validasi Periode Kupon
if ($periode_param !== now()->format('Y-m')) {
return redirect()->back()->with('error', 'Kupon kedaluwarsa atau tidak sesuai dengan periode bulan ini.');
}
$warga = PenerimaBantuan::findOrFail($id);
// Cek sudah dicairkan bulan ini
$existing = LogDistribusi::where('id_penerima', $id)
->whereMonth('tanggal_diterima', now()->month)
->whereYear('tanggal_diterima', now()->year)
->exists();
if ($existing) {
return redirect()->back()->with('error', 'Bantuan bulan ini sudah diproses.');
}
$tgl_sekarang = now();
// Upload foto penyerahan
$foto_penyerahan = '';
if ($request->hasFile('foto_penyerahan')) {
$foto_penyerahan = time() . '_bukti_' . $request->file('foto_penyerahan')->getClientOriginalName();
$request->file('foto_penyerahan')->storeAs('uploads', $foto_penyerahan, 'public');
}
LogDistribusi::create([
'id_penerima' => $id,
'tanggal_diterima' => $tgl_sekarang,
'status' => 'Menunggu',
'foto_penyerahan' => $foto_penyerahan,
]);
// Redirect back with success
$log = LogDistribusi::where('id_penerima', $id)
->whereMonth('tanggal_diterima', now()->month)
->whereYear('tanggal_diterima', now()->year)
->orderBy('tanggal_diterima', 'desc')
->first();
$warga = PenerimaBantuan::findOrFail($id);
$id_tempat = $warga->id_tempat_ibadah;
$sudah_cair = true;
$pesan_sukses = true;
return view('konfirmasi', compact('warga', 'id_tempat', 'sudah_cair', 'log', 'pesan_sukses'));
}
public function scan()
{
abort_if(auth()->user()->role === 'admin', 403, 'Akses ditolak. Halaman ini bukan untuk admin.');
return view('scan');
}
}
+152
View File
@@ -0,0 +1,152 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\PenerimaBantuan;
use App\Models\LogDistribusi;
use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\RoundBlockSizeMode;
use Endroid\QrCode\Writer\PngWriter;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
use App\Models\TempatIbadah;
class KuponController extends Controller
{
public function index(Request $request)
{
$query = PenerimaBantuan::with('tempat_ibadah')->where('status_persetujuan', 'disetujui');
// Jika admin, bisa melihat semua dan filter. Jika user, hanya melihat yang sesuai tempat ibadahnya.
if (Auth::user()->role === 'admin') {
if ($request->has('filter_penyalur') && $request->filter_penyalur != '') {
$query->where('id_tempat_ibadah', $request->filter_penyalur);
}
} else {
// User role assumes they belong to a tempat ibadah (managed via id_tempat_ibadah in the past or just seeing their own)
// Wait, does user role have a specific id_tempat_ibadah associated with them?
// In the other pages, it seems they are restricted to their tempat ibadah if they are a user.
// Let's check how PenerimaBantuanController index does it.
// But for now, let's just mimic it.
// Sebenarnya user role di tabel users tidak punya id_tempat_ibadah.
// Kita coba fetch semua disetujui saja, nanti admin filter yang berlaku.
}
$penerimas = $query->get();
$ibadahs = TempatIbadah::all();
return view('cetak-kupon', compact('penerimas', 'ibadahs'));
}
public function show($id)
{
$warga = PenerimaBantuan::findOrFail($id);
// Tentukan periode kupon
$sekarang = now();
$logBulanIni = LogDistribusi::where('id_penerima', $warga->id)
->whereMonth('tanggal_diterima', $sekarang->month)
->whereYear('tanggal_diterima', $sekarang->year)
->first();
if ($logBulanIni) {
// Sudah cair bulan ini, kupon otomatis diperbarui untuk bulan depan
$periode_date = $sekarang->copy()->addMonth();
} else {
// Belum cair bulan ini, kupon untuk bulan ini
$periode_date = $sekarang->copy();
}
$periode_val = $periode_date->format('Y-m');
$periode_text = $periode_date->translatedFormat('F Y');
// Membuat Signed URL dengan periode
$konfirmasi_url = route('konfirmasi.show', ['id' => $id, 'periode' => $periode_val]);
$signature = hash_hmac('sha256', $id . '|' . $periode_val, config('app.key'));
$signed_url = $konfirmasi_url . '&signature=' . $signature;
// Generate QR Code
try {
$builder = new Builder(
writer: new PngWriter(),
data: $signed_url,
encoding: new Encoding('UTF-8'),
errorCorrectionLevel: ErrorCorrectionLevel::High,
size: 300,
margin: 10,
roundBlockSizeMode: RoundBlockSizeMode::Margin
);
$result = $builder->build();
$qrDataUri = $result->getDataUri();
} catch (\Exception $e) {
abort(500, 'Error generating QR Code: ' . $e->getMessage());
}
$kupons = [[
'warga' => $warga,
'qrDataUri' => $qrDataUri,
'periode_text' => $periode_text
]];
return view('kupon', compact('kupons'));
}
public function cetak(Request $request)
{
$ids = $request->input('penerima_ids');
if (empty($ids) || !is_array($ids)) {
return redirect()->back()->with('error', 'Tidak ada kupon yang dipilih untuk dicetak.');
}
$wargas = PenerimaBantuan::whereIn('id', $ids)->get();
$kupons = [];
foreach ($wargas as $warga) {
$sekarang = now();
$logBulanIni = LogDistribusi::where('id_penerima', $warga->id)
->whereMonth('tanggal_diterima', $sekarang->month)
->whereYear('tanggal_diterima', $sekarang->year)
->first();
if ($logBulanIni) {
$periode_date = $sekarang->copy()->addMonth();
} else {
$periode_date = $sekarang->copy();
}
$periode_val = $periode_date->format('Y-m');
$periode_text = $periode_date->translatedFormat('F Y');
$konfirmasi_url = route('konfirmasi.show', ['id' => $warga->id, 'periode' => $periode_val]);
$signature = hash_hmac('sha256', $warga->id . '|' . $periode_val, config('app.key'));
$signed_url = $konfirmasi_url . '&signature=' . $signature;
try {
$builder = new Builder(
writer: new PngWriter(),
data: $signed_url,
encoding: new Encoding('UTF-8'),
errorCorrectionLevel: ErrorCorrectionLevel::High,
size: 300,
margin: 10,
roundBlockSizeMode: RoundBlockSizeMode::Margin
);
$result = $builder->build();
$qrDataUri = $result->getDataUri();
$kupons[] = [
'warga' => $warga,
'qrDataUri' => $qrDataUri,
'periode_text' => $periode_text
];
} catch (\Exception $e) {
// Lewati jika error
}
}
return view('kupon', compact('kupons'));
}
}
@@ -0,0 +1,63 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\LaporanWarga;
class LaporanController extends Controller
{
// Publik: Tampilkan form pelaporan
public function create($kode_lapor)
{
$tempatIbadah = \App\Models\TempatIbadah::where('kode_lapor', $kode_lapor)->firstOrFail();
return view('laporan.lapor', compact('tempatIbadah'));
}
// Publik: Simpan pelaporan
public function store(Request $request, $kode_lapor)
{
$tempatIbadah = \App\Models\TempatIbadah::where('kode_lapor', $kode_lapor)->firstOrFail();
$request->validate([
'nama_calon' => 'required|string|max:255',
'jumlah_tanggungan' => 'required|integer|min:0',
'alamat' => 'nullable|string|max:500',
'deskripsi' => 'nullable|string',
'foto' => 'nullable|image|mimes:jpeg,png,jpg|max:2048',
]);
$foto_name = null;
if ($request->hasFile('foto')) {
$file = $request->file('foto');
$foto_name = time() . '_lapor_' . $file->getClientOriginalName();
$file->storeAs('uploads', $foto_name, 'public');
}
LaporanWarga::create([
'nama_calon' => $request->nama_calon,
'jumlah_tanggungan' => $request->jumlah_tanggungan,
'alamat' => $request->alamat,
'deskripsi' => $request->deskripsi,
'foto' => $foto_name,
'status_laporan' => 'menunggu',
'id_tempat_ibadah' => $tempatIbadah->id,
]);
return redirect()->back()->with('success', 'Laporan Anda berhasil dikirim! Terima kasih atas partisipasinya.');
}
// Authenticated (Admin/User): Tampilkan daftar laporan
public function index()
{
abort_if(auth()->user()->role === 'admin', 403, 'Akses ditolak. Halaman ini bukan untuk admin.');
$tempatIbadah = \App\Models\TempatIbadah::find(auth()->user()->id_tempat_ibadah);
$laporans = LaporanWarga::where('id_tempat_ibadah', $tempatIbadah->id)
->where('status_laporan', 'menunggu')
->orderBy('created_at', 'desc')->get();
return view('laporan.index', compact('laporans', 'tempatIbadah'));
}
}
+220 -49
View File
@@ -3,27 +3,65 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Hash;
use App\Models\TempatIbadah;
use App\Models\PenerimaBantuan;
use App\Models\User;
class MapController extends Controller
{
public function index()
public function index(Request $request)
{
$ibadahs = \App\Models\TempatIbadah::all();
$penerimas = \App\Models\PenerimaBantuan::with('tempat_ibadah')->get();
return view('dashboard', compact('ibadahs', 'penerimas'));
if (Auth::user()->role === 'user') {
$ibadahs = TempatIbadah::where('id', Auth::user()->id_tempat_ibadah)->get();
$penerimas = PenerimaBantuan::with('tempat_ibadah')
->where('id_tempat_ibadah', Auth::user()->id_tempat_ibadah)->get();
} else {
$ibadahs = TempatIbadah::all();
$penerimas = PenerimaBantuan::with('tempat_ibadah')->get();
}
$laporan_fill = null;
if ($request->has('add_laporan')) {
$laporan_fill = \App\Models\LaporanWarga::find($request->add_laporan);
}
return view('dashboard', compact('ibadahs', 'penerimas', 'laporan_fill'));
}
public function daftarPenerimaBantuan()
public function daftarPenerimaBantuan(Request $request)
{
$penerimas = \App\Models\PenerimaBantuan::with('tempat_ibadah')->get();
$ibadahs = \App\Models\TempatIbadah::all();
$ibadahs = TempatIbadah::all();
$query = PenerimaBantuan::with('tempat_ibadah');
if (Auth::user()->role === 'user') {
$query->where('id_tempat_ibadah', Auth::user()->id_tempat_ibadah);
$ibadahs = TempatIbadah::where('id', Auth::user()->id_tempat_ibadah)->get();
} elseif ($request->filled('filter_penyalur')) {
$query->where('id_tempat_ibadah', (int)$request->filter_penyalur);
}
$penerimas = $query->get();
return view('daftar-penerima-bantuan', compact('penerimas', 'ibadahs'));
}
public function daftarTempatIbadah()
{
$ibadahs = \App\Models\TempatIbadah::all();
return view('daftar-tempat-ibadah', compact('ibadahs'));
if (Auth::user()->role === 'user') {
$ibadahs = TempatIbadah::where('id', Auth::user()->id_tempat_ibadah)->get();
} else {
$ibadahs = TempatIbadah::all();
}
// Include admin email for each ibadah if admin, or just fetch all users
$adminUsers = User::where('role', 'user')->get()->keyBy('id_tempat_ibadah');
return view('daftar-tempat-ibadah', compact('ibadahs', 'adminUsers'));
}
public function save(Request $request)
@@ -35,33 +73,111 @@ class MapController extends Controller
$alamat = $request->alamat;
if ($type == 'ibadah') {
\App\Models\TempatIbadah::create([
// ... (ibadah creation logic remains unchanged)
if (Auth::user()->role !== 'admin') {
return response()->json(['status' => 'error', 'message' => 'Unauthorized']);
}
$ibadah = TempatIbadah::create([
'nama_tempat' => $nama,
'jenis_tempat_ibadah' => $request->jenis_tempat_ibadah,
'kontak_person' => $request->kontak_person,
'radius_meter' => 500,
'nama_pengurus' => $request->nama_pengurus,
'kontak_pengurus' => $request->kontak_pengurus,
'lat' => $lat,
'lng' => $lng,
'radius_meter' => 500,
'alamat' => $alamat
]);
} else {
$fotoPath = null;
if ($request->hasFile('foto_kondisi_rumah')) {
$fotoPath = $request->file('foto_kondisi_rumah')->store('fotos', 'public');
$baseEmail = strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $nama));
$email = $baseEmail . '@email.com';
if (User::where('email', $email)->exists()) {
$email = $baseEmail . rand(100, 999) . '@email.com';
}
\App\Models\PenerimaBantuan::create([
User::create([
'name' => $nama,
'email' => $email,
'password' => Hash::make('password123'),
'role' => 'user',
'id_tempat_ibadah' => $ibadah->id,
]);
} else {
if (Auth::user()->role !== 'user') {
return response()->json(['status' => 'error', 'message' => 'Unauthorized']);
}
$tempatIbadah = \App\Models\TempatIbadah::find(Auth::user()->id_tempat_ibadah);
if ($tempatIbadah) {
$distance = $this->calculateDistance($tempatIbadah->lat, $tempatIbadah->lng, $lat, $lng);
if ($distance > $tempatIbadah->radius_meter) {
return response()->json([
'status' => 'error',
'message' => 'Hanya bisa di lingkaran radius pelayanan'
]);
}
}
// Pengecekan NIK dan Nomor KK Ganda
$existsNIK = \App\Models\PenerimaBantuan::where('nik_kepala_keluarga', $request->nik_kepala_keluarga)->first();
if ($existsNIK) {
return response()->json([
'status' => 'error',
'message' => 'Gagal: NIK Kepala Keluarga (' . $request->nik_kepala_keluarga . ') sudah terdaftar di dalam sistem.'
]);
}
$existsKK = \App\Models\PenerimaBantuan::where('nomor_kk', $request->nomor_kk)->first();
if ($existsKK) {
return response()->json([
'status' => 'error',
'message' => 'Gagal: Nomor Kartu Keluarga (' . $request->nomor_kk . ') sudah terdaftar di dalam sistem.'
]);
}
// Handle multi-foto upload
$foto_names = [];
if ($request->hasFile('foto')) {
$files = is_array($request->file('foto')) ? $request->file('foto') : [$request->file('foto')];
foreach ($files as $i => $file) {
$foto_name = time() . '_' . $i . '_' . $file->getClientOriginalName();
$file->storeAs('uploads', $foto_name, 'public');
$foto_names[] = $foto_name;
}
} else if ($request->filled('id_laporan_warga')) {
$laporan = \App\Models\LaporanWarga::find($request->id_laporan_warga);
if ($laporan && $laporan->foto) {
// Copy existing foto from laporan
$foto_names[] = $laporan->foto;
}
}
// Handle dokumen laporan upload
$dokumen_laporan = '';
if ($request->hasFile('dokumen_laporan')) {
$dokumen_laporan = time() . '_pdf_' . $request->file('dokumen_laporan')->getClientOriginalName();
$request->file('dokumen_laporan')->storeAs('uploads', $dokumen_laporan, 'public');
}
PenerimaBantuan::create([
'nama_kepala_keluarga' => $nama,
'id_tempat_ibadah' => $request->id_tempat_ibadah,
'id_tempat_ibadah' => Auth::user()->role === 'user' ? Auth::user()->id_tempat_ibadah : $request->id_tempat_ibadah,
'nik_kepala_keluarga' => $request->nik_kepala_keluarga,
'nomor_kk' => $request->nomor_kk,
'jumlah_tanggungan' => $request->jumlah_tanggungan,
'foto_kondisi_rumah' => $fotoPath,
'foto' => implode(',', $foto_names),
'lat' => $lat,
'lng' => $lng,
'alamat' => $alamat
'alamat' => $alamat,
'dokumen_laporan' => $dokumen_laporan,
'status_persetujuan' => 'menunggu',
]);
if ($request->filled('id_laporan_warga')) {
\App\Models\LaporanWarga::where('id', $request->id_laporan_warga)->update(['status_laporan' => 'diproses']);
}
}
$this->recalculateCoverage();
return response()->json(['status' => 'success']);
}
@@ -69,8 +185,8 @@ class MapController extends Controller
{
$id = $request->id;
$radius = $request->radius;
\App\Models\TempatIbadah::where('id', $id)->update(['radius_meter' => $radius]);
$this->checkAndUnlinkPenerima($id);
TempatIbadah::where('id', $id)->update(['radius_meter' => $radius]);
$this->recalculateCoverage();
return response()->json(['status' => 'success']);
}
@@ -82,30 +198,60 @@ class MapController extends Controller
$type = $request->type;
if ($type == 'ibadah') {
\App\Models\TempatIbadah::where('id', $id)->update([
$data = [
'nama_tempat' => $nama,
'jenis_tempat_ibadah' => $request->jenis_tempat_ibadah,
'kontak_person' => $request->kontak_person,
'alamat' => $alamat,
'radius_meter' => $request->radius_meter
]);
$this->checkAndUnlinkPenerima($id);
];
if ($request->filled('jenis_tempat_ibadah')) $data['jenis_tempat_ibadah'] = $request->jenis_tempat_ibadah;
if ($request->filled('nama_pengurus')) $data['nama_pengurus'] = $request->nama_pengurus;
if ($request->filled('kontak_pengurus')) $data['kontak_pengurus'] = $request->kontak_pengurus;
if ($request->filled('radius_meter')) $data['radius_meter'] = (int)$request->radius_meter;
TempatIbadah::where('id', $id)->update($data);
$this->recalculateCoverage();
} else {
$updateData = [
$data = [
'nama_kepala_keluarga' => $nama,
'id_tempat_ibadah' => $request->id_tempat_ibadah,
'nik_kepala_keluarga' => $request->nik_kepala_keluarga,
'nomor_kk' => $request->nomor_kk,
'jumlah_tanggungan' => $request->jumlah_tanggungan,
'alamat' => $alamat
'id_tempat_ibadah' => Auth::user()->role === 'user' ? Auth::user()->id_tempat_ibadah : $request->id_tempat_ibadah,
'alamat' => $alamat,
];
if ($request->hasFile('foto_kondisi_rumah')) {
$updateData['foto_kondisi_rumah'] = $request->file('foto_kondisi_rumah')->store('fotos', 'public');
if ($request->filled('nik_kepala_keluarga')) $data['nik_kepala_keluarga'] = $request->nik_kepala_keluarga;
if ($request->filled('nomor_kk')) $data['nomor_kk'] = $request->nomor_kk;
if ($request->has('jumlah_tanggungan')) $data['jumlah_tanggungan'] = $request->jumlah_tanggungan;
// Handle existing photos and deletions
$penerima = PenerimaBantuan::find($id);
$current_fotos = !empty($penerima->foto) ? explode(',', $penerima->foto) : [];
if ($request->has('hapus_foto') && is_array($request->hapus_foto)) {
foreach ($request->hapus_foto as $hf) {
if (($key = array_search($hf, $current_fotos)) !== false) {
unset($current_fotos[$key]);
$path = storage_path('app/public/uploads/' . $hf);
if (file_exists($path)) {
unlink($path);
}
}
}
$current_fotos = array_values($current_fotos);
}
\App\Models\PenerimaBantuan::where('id', $id)->update($updateData);
// Handle new foto uploads
if ($request->hasFile('foto')) {
$files = is_array($request->file('foto')) ? $request->file('foto') : [$request->file('foto')];
foreach ($files as $i => $file) {
$foto_name = time() . '_' . $i . '_' . $file->getClientOriginalName();
$file->storeAs('uploads', $foto_name, 'public');
$current_fotos[] = $foto_name;
}
}
$data['foto'] = implode(',', $current_fotos);
PenerimaBantuan::where('id', $id)->update($data);
}
return redirect()->back();
}
@@ -115,31 +261,56 @@ class MapController extends Controller
$type = $request->type;
if ($type == 'ibadah') {
\App\Models\TempatIbadah::where('id', $id)->delete();
TempatIbadah::where('id', $id)->delete();
} else {
\App\Models\PenerimaBantuan::where('id', $id)->delete();
PenerimaBantuan::where('id', $id)->delete();
}
$this->recalculateCoverage();
return redirect()->back();
}
private function calculateDistance($lat1, $lon1, $lat2, $lon2) {
private function calculateDistance($lat1, $lon1, $lat2, $lon2)
{
$earthRadius = 6371000; // in meters
$dLat = deg2rad($lat2 - $lat1);
$dLon = deg2rad($lon2 - $lon1);
$a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon/2) * sin($dLon/2);
$a = sin($dLat / 2) * sin($dLat / 2) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon / 2) * sin($dLon / 2);
$c = 2 * asin(sqrt($a));
return $earthRadius * $c;
}
private function checkAndUnlinkPenerima($ibadahId) {
$ibadah = \App\Models\TempatIbadah::find($ibadahId);
if (!$ibadah) return;
private function recalculateCoverage()
{
$all_ibadahs = TempatIbadah::all(['id', 'lat', 'lng', 'radius_meter']);
$penerimas = \App\Models\PenerimaBantuan::where('id_tempat_ibadah', $ibadahId)->get();
foreach ($penerimas as $penerima) {
$distance = $this->calculateDistance($ibadah->lat, $ibadah->lng, $penerima->lat, $penerima->lng);
if ($distance > $ibadah->radius_meter) {
$penerima->update(['id_tempat_ibadah' => null]);
$penerimas = PenerimaBantuan::all(['id', 'lat', 'lng']);
foreach ($penerimas as $pb) {
$best_id = null;
$min_distance = INF;
foreach ($all_ibadahs as $ib) {
$distance = $this->calculateDistance($ib->lat, $ib->lng, $pb->lat, $pb->lng);
if ($distance <= $ib->radius_meter) {
if ($distance < $min_distance) {
$min_distance = $distance;
$best_id = $ib->id;
}
}
}
if ($best_id !== null) {
PenerimaBantuan::where('id', $pb->id)->update([
'id_tempat_ibadah' => $best_id,
'jarak_ke_penyalur' => $min_distance,
]);
} else {
PenerimaBantuan::where('id', $pb->id)->update([
'id_tempat_ibadah' => null,
'jarak_ke_penyalur' => null,
]);
}
}
}
@@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\PenerimaBantuan;
use Illuminate\Support\Facades\Auth;
class PersetujuanController extends Controller
{
public function index()
{
if (Auth::user()->role !== 'admin') {
abort(403, 'Unauthorized action.');
}
// Only fetch 'menunggu' status to show in the approval table
$penerimas = PenerimaBantuan::with('tempat_ibadah')->where('status_persetujuan', 'menunggu')->get();
return view('persetujuan', compact('penerimas'));
}
public function updateStatus(Request $request, $id)
{
if (Auth::user()->role !== 'admin') {
abort(403, 'Unauthorized action.');
}
$request->validate([
'status_persetujuan' => 'required|in:disetujui,ditolak',
'alasan_penolakan' => 'nullable|string'
]);
$penerima = PenerimaBantuan::findOrFail($id);
$penerima->status_persetujuan = $request->status_persetujuan;
if ($request->status_persetujuan === 'ditolak') {
$penerima->alasan_penolakan = $request->alasan_penolakan;
} else {
$penerima->alasan_penolakan = null;
}
$penerima->save();
return redirect()->back()->with('success', 'Status berhasil diperbarui!');
}
}
+144
View File
@@ -0,0 +1,144 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\LogDistribusi;
use App\Models\PenerimaBantuan;
use Barryvdh\DomPDF\Facade\Pdf;
class RiwayatController extends Controller
{
public function index(Request $request)
{
$query = LogDistribusi::with(['penerimaBantuan.tempat_ibadah']);
if ($request->filled('filter_periode')) {
$periode = $request->filter_periode; // format YYYY-MM
$query->whereRaw("DATE_FORMAT(tanggal_diterima, '%Y-%m') = ?", [$periode]);
}
$riwayats = $query->orderBy('tanggal_diterima', 'desc')->get();
return view('riwayat', compact('riwayats'));
}
public function konfirmasiPenyaluran($id_log)
{
$log = LogDistribusi::where('id', $id_log)->where('status', 'Menunggu')->first();
if ($log) {
$log->update(['status' => 'Selesai']);
PenerimaBantuan::where('id', $log->id_penerima)
->update(['tanggal_pencairan_terakhir' => $log->tanggal_diterima]);
}
return redirect()->back();
}
public function cetakPdf(Request $request)
{
if (!$request->filled('periode')) {
abort(400, 'Periode tidak valid!');
}
$periode = $request->periode;
$periode_obj = date_create_from_format('Y-m', $periode);
if (!$periode_obj) {
abort(400, 'Format periode tidak valid!');
}
$bulan_indonesia = [
'January' => 'Januari', 'February' => 'Februari', 'March' => 'Maret',
'April' => 'April', 'May' => 'Mei', 'June' => 'Juni',
'July' => 'Juli', 'August' => 'Agustus', 'September' => 'September',
'October' => 'Oktober', 'November' => 'November', 'December' => 'Desember'
];
$bulan_eng = date_format($periode_obj, 'F');
$tahun = date_format($periode_obj, 'Y');
$bulan_tahun = $bulan_indonesia[$bulan_eng] . ' ' . $tahun;
$riwayats = LogDistribusi::with(['penerimaBantuan.tempat_ibadah'])
->whereRaw("DATE_FORMAT(tanggal_diterima, '%Y-%m') = ?", [$periode])
->orderBy('tanggal_diterima', 'desc')
->get();
if ($riwayats->isEmpty()) {
abort(404, 'Data riwayat tidak ditemukan untuk periode ini!');
}
$tgl_sekarang_indo = date('d') . ' ' . $bulan_indonesia[date('F')] . ' ' . date('Y');
$html = '
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Laporan Riwayat Penyaluran Bantuan - ' . $bulan_tahun . '</title>
<style>
body { font-family: Arial, sans-serif; font-size: 12px; color: #333; }
h1 { text-align: center; font-size: 18px; text-transform: uppercase; margin-bottom: 5px; }
h3 { text-align: center; font-size: 14px; margin-top: 0; margin-bottom: 20px; font-weight: normal; }
table { width: 100%; border-collapse: collapse; margin-top: 15px; }
th, td { border: 1px solid #000; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>Laporan Riwayat Penyaluran Bantuan</h1>
<h3>Periode: ' . $bulan_tahun . '</h3>
<table>
<thead>
<tr>
<th>No</th>
<th>Tanggal Terima</th>
<th>Nama Kepala Keluarga</th>
<th>NIK</th>
<th>Alamat</th>
<th>Penyalur</th>
<th>Status</th>
</tr>
</thead>
<tbody>';
$no = 1;
foreach ($riwayats as $r) {
$tgl = $r->tanggal_diterima->format('d-m-Y H:i');
$nama_kk = $r->penerimaBantuan->nama_kepala_keluarga ?? 'Data Terhapus';
$nik = $r->penerimaBantuan && $r->penerimaBantuan->nik_kepala_keluarga
? substr($r->penerimaBantuan->nik_kepala_keluarga, 0, 6) . '**********'
: '-';
$alamat = $r->penerimaBantuan->alamat ?? '-';
$penyalur = $r->penerimaBantuan && $r->penerimaBantuan->tempat_ibadah
? $r->penerimaBantuan->tempat_ibadah->nama_tempat
: '-';
$html .= '
<tr>
<td style="text-align: center;">' . $no . '</td>
<td>' . $tgl . '</td>
<td>' . e($nama_kk) . '</td>
<td>' . $nik . '</td>
<td>' . e($alamat) . '</td>
<td>' . e($penyalur) . '</td>
<td style="text-align: center;">' . $r->status . '</td>
</tr>';
$no++;
}
$html .= '
</tbody>
</table>
<div style="margin-top: 50px; text-align: right; padding-right: 50px;">
Pontianak, ' . $tgl_sekarang_indo . '<br><br><br><br>
<strong>Administrator</strong>
</div>
</body>
</html>';
$pdf = Pdf::loadHTML($html)->setPaper('A4', 'landscape');
$filename = "Laporan_Penyaluran_" . $periode . ".pdf";
return $pdf->stream($filename);
}
}