diff --git a/app/Http/Controllers/AnggotaKeluargaController.php b/app/Http/Controllers/AnggotaKeluargaController.php new file mode 100644 index 0000000..c8dd48a --- /dev/null +++ b/app/Http/Controllers/AnggotaKeluargaController.php @@ -0,0 +1,71 @@ +orderBy('hubungan') + ->get() + ->map(fn($a) => [ + 'id' => $a->id, + 'nama' => $a->nama, + 'hubungan' => $a->hubungan, + 'jenis_kelamin' => $a->jenis_kelamin, + 'tanggal_lahir' => $a->tanggal_lahir?->format('Y-m-d'), + 'umur' => $a->umur, + 'pendidikan' => $a->pendidikan, + 'status_hidup' => $a->status_hidup, + ]); + return response()->json($anggota); + } + + public function store(Request $request, string $idRumah) + { + RumahMiskin::findOrFail($idRumah); + $validated = $request->validate([ + 'nama' => 'required|string|max:255', + 'hubungan' => 'required|in:kepala_keluarga,istri,anak,orang_tua,lainnya', + 'jenis_kelamin' => 'nullable|in:laki_laki,perempuan', + 'tanggal_lahir' => 'nullable|date|before:today', + 'pendidikan' => 'nullable|in:tidak_sekolah,sd,smp,sma,d3,s1_plus', + 'status_hidup' => 'required|in:hidup,meninggal', + ]); + $anggota = AnggotaKeluarga::create(['id_rumah' => $idRumah, ...$validated]); + ActivityLog::record('create', "Tambah anggota: {$anggota->nama} ({$idRumah})", 'anggota', $anggota->id); + return response()->json(['success' => true, 'data' => $anggota]); + } + + public function update(Request $request, string $idRumah, int $id) + { + $anggota = AnggotaKeluarga::where('id_rumah', $idRumah)->findOrFail($id); + $validated = $request->validate([ + 'nama' => 'required|string|max:255', + 'hubungan' => 'required|in:kepala_keluarga,istri,anak,orang_tua,lainnya', + 'jenis_kelamin' => 'nullable|in:laki_laki,perempuan', + 'tanggal_lahir' => 'nullable|date|before:today', + 'pendidikan' => 'nullable|in:tidak_sekolah,sd,smp,sma,d3,s1_plus', + 'status_hidup' => 'required|in:hidup,meninggal', + ]); + $anggota->update($validated); + ActivityLog::record('update', "Update anggota: {$anggota->nama} ({$idRumah})", 'anggota', $anggota->id); + return response()->json(['success' => true]); + } + + public function destroy(string $idRumah, int $id) + { + $anggota = AnggotaKeluarga::where('id_rumah', $idRumah)->findOrFail($id); + $nama = $anggota->nama; + $anggota->delete(); + ActivityLog::record('delete', "Hapus anggota: {$nama} ({$idRumah})", 'anggota', $id); + return response()->json(['success' => true]); + } +} diff --git a/app/Http/Controllers/BantuanController.php b/app/Http/Controllers/BantuanController.php new file mode 100644 index 0000000..f8ec3af --- /dev/null +++ b/app/Http/Controllers/BantuanController.php @@ -0,0 +1,56 @@ +with(['ibadah:id,nama', 'pencatat:id,name']) + ->orderByDesc('tanggal_bantuan') + ->get() + ->map(fn($b) => [ + 'id' => $b->id, + 'jenis_bantuan' => $b->jenis_bantuan, + 'keterangan' => $b->keterangan, + 'tanggal_bantuan' => $b->tanggal_bantuan->format('d/m/Y'), + 'ibadah_nama' => $b->ibadah?->nama, + 'pencatat_nama' => $b->pencatat?->name ?? 'Sistem', + ]); + return response()->json($bantuan); + } + + public function store(Request $request, string $idRumah) + { + RumahMiskin::findOrFail($idRumah); + $validated = $request->validate([ + 'jenis_bantuan' => 'required|string|max:255', + 'keterangan' => 'nullable|string', + 'tanggal_bantuan' => 'required|date', + 'ibadah_id' => 'nullable|integer|exists:rumah_ibadah,id', + ]); + $bantuan = RiwayatBantuan::create([ + 'id_rumah' => $idRumah, + 'dicatat_oleh' => auth()->id(), + ...$validated, + ]); + ActivityLog::record('create', "Catat bantuan: {$bantuan->jenis_bantuan} → {$idRumah}", 'bantuan', $bantuan->id); + return response()->json(['success' => true, 'data' => $bantuan]); + } + + public function destroy(string $idRumah, int $id) + { + $bantuan = RiwayatBantuan::where('id_rumah', $idRumah)->findOrFail($id); + $jenis = $bantuan->jenis_bantuan; + $bantuan->delete(); + ActivityLog::record('delete', "Hapus riwayat bantuan: {$jenis} ({$idRumah})", 'bantuan', $id); + return response()->json(['success' => true]); + } +} diff --git a/app/Http/Controllers/TransferController.php b/app/Http/Controllers/TransferController.php new file mode 100644 index 0000000..752d0ac --- /dev/null +++ b/app/Http/Controllers/TransferController.php @@ -0,0 +1,86 @@ +user(); + $query = PermohonanTransfer::with([ + 'dariIbadah:id,nama', 'keIbadah:id,nama', + 'rumahMiskin:id_rumah,nama_kk', 'pengaju:id,name', + ])->orderByDesc('created_at'); + + if ($user->hasRole('pengurus_ibadah')) { + $ibadahIds = RumahIbadah::where('user_id', $user->id)->pluck('id'); + $query->where(function ($q) use ($ibadahIds) { + $q->whereIn('dari_ibadah_id', $ibadahIds) + ->orWhereIn('ke_ibadah_id', $ibadahIds); + }); + } + + return response()->json($query->limit(100)->get()->map(fn($p) => [ + 'id' => $p->id, + 'dari_ibadah' => $p->dariIbadah?->nama, + 'ke_ibadah' => $p->keIbadah?->nama, + 'ke_ibadah_id' => $p->ke_ibadah_id, + 'id_rumah' => $p->id_rumah, + 'nama_kk' => $p->rumahMiskin?->nama_kk, + 'alasan' => $p->alasan, + 'status' => $p->status, + 'catatan_respons' => $p->catatan_respons, + 'diajukan_oleh' => $p->pengaju?->name, + 'created_at' => $p->created_at?->format('d/m/Y H:i'), + ])); + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'dari_ibadah_id' => 'required|integer|exists:rumah_ibadah,id', + 'ke_ibadah_id' => 'required|integer|exists:rumah_ibadah,id|different:dari_ibadah_id', + 'id_rumah' => 'required|string|exists:rumah_miskin,id_rumah', + 'alasan' => 'required|string|max:1000', + ]); + $permohonan = PermohonanTransfer::create([ + ...$validated, + 'diajukan_oleh' => auth()->id(), + 'status' => 'pending', + ]); + ActivityLog::record('create', "Ajukan transfer: {$permohonan->id_rumah} → ibadah #{$permohonan->ke_ibadah_id}", 'transfer', $permohonan->id); + return response()->json(['success' => true, 'data' => $permohonan]); + } + + public function respond(Request $request, int $id) + { + $permohonan = PermohonanTransfer::findOrFail($id); + if ($permohonan->status !== 'pending') { + return response()->json(['message' => 'Permohonan sudah diproses'], 422); + } + + $validated = $request->validate([ + 'status' => 'required|in:disetujui,ditolak', + 'catatan_respons' => 'nullable|string|max:500', + ]); + + $user = auth()->user(); + if (!$user->hasRole('administrator')) { + $ibadahIds = RumahIbadah::where('user_id', $user->id)->pluck('id'); + if (!$ibadahIds->contains($permohonan->ke_ibadah_id)) { + return response()->json(['message' => 'Tidak berhak memproses'], 403); + } + } + + $permohonan->update([...$validated, 'diproses_oleh' => $user->id]); + + $label = $validated['status'] === 'disetujui' ? 'disetujui' : 'ditolak'; + ActivityLog::record('update', "Transfer {$label}: permohonan #{$id}", 'transfer', $id); + return response()->json(['success' => true]); + } +} diff --git a/routes/web.php b/routes/web.php index 29770ee..f741340 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,13 +2,16 @@ use App\Http\Controllers\ActivityLogController; use App\Http\Controllers\AdminUserController; +use App\Http\Controllers\AnggotaKeluargaController; use App\Http\Controllers\AuthController; use App\Http\Controllers\BackupController; +use App\Http\Controllers\BantuanController; use App\Http\Controllers\ExportController; use App\Http\Controllers\IbadahController; use App\Http\Controllers\ImportController; use App\Http\Controllers\MiskinController; use App\Http\Controllers\SettingController; +use App\Http\Controllers\TransferController; use Illuminate\Support\Facades\Route; // Auth routes (public, redirect to /map if already logged in) @@ -24,6 +27,7 @@ Route::middleware('auth')->group(function () { Route::get('/map', fn() => view('map')); Route::get('/data', fn() => view('data')); Route::get('/dashboard', fn() => view('dashboard'))->name('dashboard'); + Route::get('/permohonan', fn() => view('permohonan'))->name('permohonan'); // Export routes — semua role authenticated bisa ekspor Route::get('/export/pdf', [ExportController::class, 'allMiskinPDF'])->name('export.pdf.all'); @@ -34,6 +38,28 @@ Route::middleware('auth')->group(function () { // API routes moved here for session + CSRF middleware Route::prefix('api')->group(function () { + // Anggota Keluarga — baca: semua; tulis: administrator + petugas_pendataan + Route::get('/miskin/{id}/anggota', [AnggotaKeluargaController::class, 'index']); + Route::middleware('role:administrator|petugas_pendataan')->group(function () { + Route::post('/miskin/{id}/anggota', [AnggotaKeluargaController::class, 'store']); + Route::put('/miskin/{id}/anggota/{aid}', [AnggotaKeluargaController::class, 'update']); + Route::delete('/miskin/{id}/anggota/{aid}', [AnggotaKeluargaController::class, 'destroy']); + }); + + // Riwayat Bantuan — baca: semua; tulis: administrator + petugas + pengurus_ibadah + Route::get('/miskin/{id}/bantuan', [BantuanController::class, 'index']); + Route::middleware('role:administrator|petugas_pendataan|pengurus_ibadah')->group(function () { + Route::post('/miskin/{id}/bantuan', [BantuanController::class, 'store']); + Route::delete('/miskin/{id}/bantuan/{bid}', [BantuanController::class, 'destroy']); + }); + + // Permohonan Transfer — lihat: semua; ajukan+proses: pengurus + admin + Route::get('/permohonan', [TransferController::class, 'index']); + Route::middleware('role:administrator|pengurus_ibadah')->group(function () { + Route::post('/permohonan', [TransferController::class, 'store']); + Route::put('/permohonan/{id}/respond', [TransferController::class, 'respond']); + }); + // Notifikasi — semua role authenticated Route::get('/notifications', function (\Illuminate\Http\Request $request) { $since = $request->query('since');