diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..8bf1dbb --- /dev/null +++ b/.htaccess @@ -0,0 +1,21 @@ + + + Options -MultiViews -Indexes + + + RewriteEngine On + + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + RewriteCond %{HTTP:x-xsrf-token} . + RewriteRule .* - [E=HTTP_X_XSRF_TOKEN:%{HTTP:X-XSRF-Token}] + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + \ No newline at end of file diff --git a/app/Http/Controllers/Admin/FilterisasiController.php b/app/Http/Controllers/Admin/FilterisasiController.php index 3ba7859..7d99f15 100644 --- a/app/Http/Controllers/Admin/FilterisasiController.php +++ b/app/Http/Controllers/Admin/FilterisasiController.php @@ -91,14 +91,12 @@ public function tetapkan(Request $request) $topIds = $allCandidates->take($kuota)->pluck('id')->all(); $allIds = $allCandidates->pluck('id')->all(); - // Top kuota = disetujui if (!empty($topIds)) { CalonPenerima::whereIn('id', $topIds)->update([ 'status_verifikasi' => 'disetujui', ]); } - // Sisanya = ditolak $notPickedIds = array_diff($allIds, $topIds); if (!empty($notPickedIds)) { @@ -107,7 +105,6 @@ public function tetapkan(Request $request) ]); } - // Ambil ulang data final setelah status diperbarui $finalCandidates = CalonPenerima::query() ->with(['rt.dusun', 'prediksiKelayakan']) ->whereIn('id', $allIds) @@ -118,7 +115,7 @@ public function tetapkan(Request $request) PenerimaFinal::updateOrCreate( [ - 'nik' => $candidate->nik, + 'nik' => $candidate->nik, 'periode_bantuan' => '2026 Triwulan 1', ], [ @@ -131,6 +128,9 @@ public function tetapkan(Request $request) 'penghasilan' => $candidate->penghasilan ?? 0, 'jumlah_tanggungan' => $candidate->jumlah_tanggungan ?? 0, 'aset_kepemilikan' => $candidate->aset_kepemilikan ?? '-', + 'kondisi_rumah' => $candidate->kondisi_rumah ?? 'Tidak Diketahui', + 'meteran_listrik' => $candidate->meteran_listrik ?? 'Tidak Diketahui', + 'sumber_air' => $candidate->sumber_air ?? 'Tidak Diketahui', 'bantuan_lain' => $candidate->bantuan_lain ?? 'tidak', 'usia' => $candidate->usia ?? 0, 'probability' => $probability, diff --git a/app/Http/Controllers/Auth/Manualpasswordresetcontroller.php b/app/Http/Controllers/Auth/Manualpasswordresetcontroller.php new file mode 100644 index 0000000..04d0ceb --- /dev/null +++ b/app/Http/Controllers/Auth/Manualpasswordresetcontroller.php @@ -0,0 +1,83 @@ +validate([ + 'email' => ['required', 'email'], + ]); + + $found = User::where('email', $validated['email'])->exists(); + + return response()->json(['found' => $found]); + + } catch (\Illuminate\Validation\ValidationException $e) { + return response()->json([ + 'found' => false, + 'message' => collect($e->errors())->flatten()->first(), + ], 422); + + } catch (\Exception $e) { + return response()->json([ + 'found' => false, + 'message' => 'Terjadi kesalahan server: ' . $e->getMessage(), + ], 500); + } + } + + /** + * AJAX: update password berdasarkan email yang sudah diverifikasi. + * POST /password/manual/update + */ + public function updatePassword(Request $request) + { + try { + $validated = $request->validate([ + 'email' => ['required', 'email', 'exists:users,email'], + 'password' => ['required', 'confirmed', Password::min(8)], + 'password_confirmation' => ['required'], + ]); + + $user = User::where('email', $validated['email'])->firstOrFail(); + $user->update([ + 'password' => Hash::make($validated['password']), + ]); + + return response()->json(['success' => true]); + + } catch (\Illuminate\Validation\ValidationException $e) { + return response()->json([ + 'success' => false, + 'message' => collect($e->errors())->flatten()->first(), + ], 422); + + } catch (\Exception $e) { + return response()->json([ + 'success' => false, + 'message' => 'Terjadi kesalahan server: ' . $e->getMessage(), + ], 500); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Auth/PasswordResetLinkController.php b/app/Http/Controllers/Auth/PasswordResetLinkController.php index bf1ebfa..fca9377 100644 --- a/app/Http/Controllers/Auth/PasswordResetLinkController.php +++ b/app/Http/Controllers/Auth/PasswordResetLinkController.php @@ -6,6 +6,7 @@ use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Password; +use Illuminate\Support\Facades\Log; use Illuminate\View\View; class PasswordResetLinkController extends Controller @@ -29,6 +30,10 @@ public function store(Request $request): RedirectResponse 'email' => ['required', 'email'], ]); + Log::info('TES RESET PASSWORD MASUK', [ + 'email' => $request->email, + ]); + // We will send the password reset link to this user. Once we have attempted // to send the link, we will examine the response then see the message we // need to show to the user. Finally, we'll send out a proper response. @@ -41,4 +46,4 @@ public function store(Request $request): RedirectResponse : back()->withInput($request->only('email')) ->withErrors(['email' => __($status)]); } -} +} \ No newline at end of file diff --git a/app/Http/Controllers/Rt/CalonPenerimaController.php b/app/Http/Controllers/Rt/CalonPenerimaController.php index 620bacf..b8eb948 100644 --- a/app/Http/Controllers/Rt/CalonPenerimaController.php +++ b/app/Http/Controllers/Rt/CalonPenerimaController.php @@ -10,6 +10,7 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Storage; class CalonPenerimaController extends Controller { @@ -34,15 +35,12 @@ public function index() public function create() { - // RT tidak boleh pilih RT lain - // Tapi kita biarkan view create tetap bisa pakai data RT user (kalau mau ditampilkan) $user = Auth::user(); $rts = RT::where('id', $user->rt_id) ->with('dusun') ->get(); - // fallback kalau data RT user belum ada (harusnya jarang terjadi) if ($rts->isEmpty()) { $rts = RT::with('dusun')->get(); } @@ -60,75 +58,107 @@ public function store(Request $request) } $validated = $request->validate([ - // rt_id boleh ada di form, tapi akan kita override (anti inject) - 'rt_id' => 'nullable|exists:rts,id', - - // โœ… NIK & NO KK TIDAK BOLEH DUPLIKAT - 'no_kk' => 'required|digits:16|unique:calon_penerimas,no_kk', - 'nik' => 'required|digits:16|unique:calon_penerimas,nik', - - 'nama_lengkap' => 'required|string|max:255', - 'jenis_kelamin' => 'required|in:Laki-laki,Perempuan', - 'tempat_lahir' => 'required|string|max:255', - 'tanggal_lahir' => 'required|date', - 'alamat' => 'required|string', - 'desa' => 'nullable|string|max:255', // akan kita set otomatis - 'pekerjaan' => 'required|string', - 'penghasilan' => 'required|numeric|min:0', - 'jumlah_tanggungan' => 'required|integer|min:0', - 'aset_kepemilikan' => 'required|string', - 'bantuan_lain' => 'required|in:ya,tidak', - 'usia' => 'required|integer|min:17|max:100', - 'status_perkawinan' => 'required|string', + 'rt_id' => 'nullable|exists:rts,id', + 'no_kk' => 'required|digits:16|unique:calon_penerimas,no_kk', + 'nik' => 'required|digits:16|unique:calon_penerimas,nik', + 'nama_lengkap' => 'required|string|max:255', + 'jenis_kelamin' => 'required|in:Laki-laki,Perempuan', + 'tempat_lahir' => 'required|string|max:255', + 'tanggal_lahir' => 'required|date', + 'alamat' => 'required|string', + 'desa' => 'nullable|string|max:255', + 'pekerjaan' => 'required|string', + 'penghasilan' => 'required|numeric|min:0', + 'jumlah_tanggungan' => 'required|integer|min:0', + 'aset_kepemilikan' => 'required|string', + 'bantuan_lain' => 'required|in:ya,tidak', + 'usia' => 'required|integer|min:17|max:100', + 'status_perkawinan' => 'required|string', + 'kondisi_rumah' => 'required|in:Layak,Sedang,Tidak Layak', + 'meteran_listrik' => 'required|in:450VA,900VA,1300VA+', + 'sumber_air' => 'required|in:PDAM,Sumur,Sungai', + // Upload foto (opsional) + 'foto_rumah_depan' => 'nullable|image|max:2048', + 'foto_rumah_belakang' => 'nullable|image|max:2048', + 'foto_rumah_kanan' => 'nullable|image|max:2048', + 'foto_rumah_kiri' => 'nullable|image|max:2048', + 'foto_kk' => 'nullable|image|max:2048', + 'foto_ktp' => 'nullable|image|max:2048', + 'foto_rekening_listrik' => 'nullable|mimes:jpg,jpeg,png,pdf|max:2048', + 'foto_meteran_air' => 'nullable|image|max:2048', + 'dokumen_pendukung' => 'nullable|mimes:jpg,jpeg,png,pdf,doc,docx|max:5120', ], [ - 'nik.unique' => 'NIK sudah pernah diinput.', + 'nik.unique' => 'NIK sudah pernah diinput.', 'no_kk.unique' => 'No. KK sudah pernah diinput.', ]); - // ๐Ÿ”’ Kunci RT dari user login (anti inject) $validated['rt_id'] = $myRtId; - // ๐Ÿ”’ Kunci Dusun/Desa ikut RT $rt = RT::with('dusun')->find($myRtId); if ($rt && $rt->dusun) { $validated['desa'] = $rt->dusun->nama_dusun; } else { - // fallback aman kalau relasi dusun kosong $validated['desa'] = $validated['desa'] ?? '-'; } DB::beginTransaction(); try { + // Handle upload foto + $fotoFields = [ + 'foto_rumah_depan', 'foto_rumah_belakang', 'foto_rumah_kanan', 'foto_rumah_kiri', + 'foto_kk', 'foto_ktp', 'foto_rekening_listrik', 'foto_meteran_air', 'dokumen_pendukung', + ]; + foreach ($fotoFields as $field) { + if ($request->hasFile($field)) { + $validated[$field] = $request->file($field)->store('dokumen-warga', 'public'); + } + } + $calonPenerima = CalonPenerima::create([ - 'user_id' => $user->id, - 'rt_id' => $validated['rt_id'], - 'no_kk' => $validated['no_kk'], - 'nik' => $validated['nik'], - 'nama_lengkap' => $validated['nama_lengkap'], - 'jenis_kelamin' => $validated['jenis_kelamin'], - 'tempat_lahir' => $validated['tempat_lahir'], - 'tanggal_lahir' => $validated['tanggal_lahir'], - 'alamat' => $validated['alamat'], - 'desa' => $validated['desa'], - 'pekerjaan' => $validated['pekerjaan'], - 'penghasilan' => $validated['penghasilan'], - 'jumlah_tanggungan' => $validated['jumlah_tanggungan'], - 'aset_kepemilikan' => $validated['aset_kepemilikan'], - 'bantuan_lain' => $validated['bantuan_lain'], - 'usia' => $validated['usia'], - 'status_perkawinan' => $validated['status_perkawinan'], - 'status_verifikasi' => 'pending', - 'tracking_status' => 'draft', + 'user_id' => $user->id, + 'rt_id' => $validated['rt_id'], + 'no_kk' => $validated['no_kk'], + 'nik' => $validated['nik'], + 'nama_lengkap' => $validated['nama_lengkap'], + 'jenis_kelamin' => $validated['jenis_kelamin'], + 'tempat_lahir' => $validated['tempat_lahir'], + 'tanggal_lahir' => $validated['tanggal_lahir'], + 'alamat' => $validated['alamat'], + 'desa' => $validated['desa'], + 'pekerjaan' => $validated['pekerjaan'], + 'penghasilan' => $validated['penghasilan'], + 'jumlah_tanggungan' => $validated['jumlah_tanggungan'], + 'aset_kepemilikan' => $validated['aset_kepemilikan'], + 'kondisi_rumah' => $validated['kondisi_rumah'], + 'meteran_listrik' => $validated['meteran_listrik'], + 'sumber_air' => $validated['sumber_air'], + 'bantuan_lain' => $validated['bantuan_lain'], + 'usia' => $validated['usia'], + 'status_perkawinan' => $validated['status_perkawinan'], + 'status_verifikasi' => 'pending', + 'tracking_status' => 'draft', + 'foto_rumah_depan' => $validated['foto_rumah_depan'] ?? null, + 'foto_rumah_belakang' => $validated['foto_rumah_belakang'] ?? null, + 'foto_rumah_kanan' => $validated['foto_rumah_kanan'] ?? null, + 'foto_rumah_kiri' => $validated['foto_rumah_kiri'] ?? null, + 'foto_kk' => $validated['foto_kk'] ?? null, + 'foto_ktp' => $validated['foto_ktp'] ?? null, + 'foto_rekening_listrik' => $validated['foto_rekening_listrik'] ?? null, + 'foto_meteran_air' => $validated['foto_meteran_air'] ?? null, + 'dokumen_pendukung' => $validated['dokumen_pendukung'] ?? null, ]); - // ๐Ÿ”ฎ ML Prediction + // ML Prediction $predictionData = [ - 'pekerjaan' => $validated['pekerjaan'], - 'penghasilan' => $validated['penghasilan'], + 'pekerjaan' => $validated['pekerjaan'], + 'penghasilan' => $validated['penghasilan'], 'jumlah_tanggungan' => $validated['jumlah_tanggungan'], - 'aset_kepemilikan' => $validated['aset_kepemilikan'], - 'bantuan_lain' => $validated['bantuan_lain'], - 'usia' => $validated['usia'], + 'aset_kepemilikan' => $validated['aset_kepemilikan'], + 'bantuan_lain' => $validated['bantuan_lain'], + 'usia' => $validated['usia'], + 'kondisi_rumah' => $validated['kondisi_rumah'], + 'meteran_listrik' => $validated['meteran_listrik'], + 'sumber_air' => $validated['sumber_air'], ]; $prediction = $this->mlService->getPrediction($predictionData); @@ -136,8 +166,11 @@ public function store(Request $request) if ($prediction) { PrediksiKelayakan::create([ 'calon_penerima_id' => $calonPenerima->id, - 'probability' => $prediction['probability'], - 'recommendation' => $prediction['recommendation'], + 'probability' => $prediction['probability'], + 'recommendation' => $prediction['recommendation'], + 'kondisi_rumah' => $validated['kondisi_rumah'], + 'meteran_listrik' => $validated['meteran_listrik'], + 'sumber_air' => $validated['sumber_air'], ]); } @@ -147,10 +180,7 @@ public function store(Request $request) ->with('success', 'Data calon penerima berhasil ditambahkan!'); } catch (\Exception $e) { DB::rollBack(); - - return back() - ->withInput() - ->with('error', 'Terjadi kesalahan: ' . $e->getMessage()); + return back()->withInput()->with('error', 'Terjadi kesalahan: ' . $e->getMessage()); } } @@ -158,7 +188,6 @@ public function show(CalonPenerima $calonPenerima) { $user = Auth::user(); - // ๐Ÿ”’ RT hanya boleh lihat data miliknya if ($calonPenerima->user_id !== $user->id) { abort(403, 'Unauthorized action.'); } @@ -174,7 +203,6 @@ public function edit(CalonPenerima $calonPenerima) { $user = Auth::user(); - // ๐Ÿ”’ RT hanya bisa edit kalau miliknya + masih draft if ($calonPenerima->user_id !== $user->id || ($calonPenerima->tracking_status ?? 'draft') !== 'draft') { abort(403, 'Data yang sudah diajukan tidak dapat diubah.'); } @@ -186,7 +214,6 @@ public function update(Request $request, CalonPenerima $calonPenerima) { $user = Auth::user(); - // ๐Ÿ”’ RT hanya bisa update kalau miliknya + masih draft if ($calonPenerima->user_id !== $user->id || ($calonPenerima->tracking_status ?? 'draft') !== 'draft') { abort(403, 'Data yang sudah diajukan tidak dapat diubah.'); } @@ -197,34 +224,41 @@ public function update(Request $request, CalonPenerima $calonPenerima) } $validated = $request->validate([ - 'rt_id' => 'nullable|exists:rts,id', - - // โœ… UNIQUE KECUALI DATA SENDIRI - 'no_kk' => 'required|digits:16|unique:calon_penerimas,no_kk,' . $calonPenerima->id, - 'nik' => 'required|digits:16|unique:calon_penerimas,nik,' . $calonPenerima->id, - - 'nama_lengkap' => 'required|string|max:255', - 'jenis_kelamin' => 'required|in:Laki-laki,Perempuan', - 'tempat_lahir' => 'required|string|max:255', - 'tanggal_lahir' => 'required|date', - 'alamat' => 'required|string', - 'desa' => 'nullable|string|max:255', // akan di-override - 'pekerjaan' => 'required|string', - 'penghasilan' => 'required|numeric|min:0', - 'jumlah_tanggungan' => 'required|integer|min:0', - 'aset_kepemilikan' => 'required|string', - 'bantuan_lain' => 'required|in:ya,tidak', - 'usia' => 'required|integer|min:17|max:100', - 'status_perkawinan' => 'required|string', + 'rt_id' => 'nullable|exists:rts,id', + 'no_kk' => 'required|digits:16|unique:calon_penerimas,no_kk,' . $calonPenerima->id, + 'nik' => 'required|digits:16|unique:calon_penerimas,nik,' . $calonPenerima->id, + 'nama_lengkap' => 'required|string|max:255', + 'jenis_kelamin' => 'required|in:Laki-laki,Perempuan', + 'tempat_lahir' => 'required|string|max:255', + 'tanggal_lahir' => 'required|date', + 'alamat' => 'required|string', + 'desa' => 'nullable|string|max:255', + 'pekerjaan' => 'required|string', + 'penghasilan' => 'required|numeric|min:0', + 'jumlah_tanggungan' => 'required|integer|min:0', + 'aset_kepemilikan' => 'required|string', + 'bantuan_lain' => 'required|in:ya,tidak', + 'usia' => 'required|integer|min:17|max:100', + 'status_perkawinan' => 'required|string', + 'kondisi_rumah' => 'required|in:Layak,Sedang,Tidak Layak', + 'meteran_listrik' => 'required|in:450VA,900VA,1300VA+', + 'sumber_air' => 'required|in:PDAM,Sumur,Sungai', + 'foto_rumah_depan' => 'nullable|image|max:2048', + 'foto_rumah_belakang' => 'nullable|image|max:2048', + 'foto_rumah_kanan' => 'nullable|image|max:2048', + 'foto_rumah_kiri' => 'nullable|image|max:2048', + 'foto_kk' => 'nullable|image|max:2048', + 'foto_ktp' => 'nullable|image|max:2048', + 'foto_rekening_listrik' => 'nullable|mimes:jpg,jpeg,png,pdf|max:2048', + 'foto_meteran_air' => 'nullable|image|max:2048', + 'dokumen_pendukung' => 'nullable|mimes:jpg,jpeg,png,pdf,doc,docx|max:5120', ], [ - 'nik.unique' => 'NIK sudah pernah diinput.', + 'nik.unique' => 'NIK sudah pernah diinput.', 'no_kk.unique' => 'No. KK sudah pernah diinput.', ]); - // ๐Ÿ”’ Kunci RT dari user login (anti inject) $validated['rt_id'] = $myRtId; - // ๐Ÿ”’ Kunci Dusun/Desa ikut RT $rt = RT::with('dusun')->find($myRtId); if ($rt && $rt->dusun) { $validated['desa'] = $rt->dusun->nama_dusun; @@ -234,29 +268,45 @@ public function update(Request $request, CalonPenerima $calonPenerima) DB::beginTransaction(); try { + // Handle upload foto โ€” hapus lama kalau ada yang baru + $fotoFields = [ + 'foto_rumah_depan', 'foto_rumah_belakang', 'foto_rumah_kanan', 'foto_rumah_kiri', + 'foto_kk', 'foto_ktp', 'foto_rekening_listrik', 'foto_meteran_air', 'dokumen_pendukung', + ]; + foreach ($fotoFields as $field) { + if ($request->hasFile($field)) { + if ($calonPenerima->$field) { + Storage::disk('public')->delete($calonPenerima->$field); + } + $validated[$field] = $request->file($field)->store('dokumen-warga', 'public'); + } + } + $calonPenerima->update($validated); - // (Opsional) Kalau kamu mau: update ulang prediksi ML saat data diupdate - // Kalau mau aktif, uncomment ini: - /* + // Uncomment kalau mau update ulang prediksi ML saat edit $predictionData = [ - 'pekerjaan' => $validated['pekerjaan'], - 'penghasilan' => $validated['penghasilan'], + 'pekerjaan' => $validated['pekerjaan'], + 'penghasilan' => $validated['penghasilan'], 'jumlah_tanggungan' => $validated['jumlah_tanggungan'], - 'aset_kepemilikan' => $validated['aset_kepemilikan'], - 'bantuan_lain' => $validated['bantuan_lain'], - 'usia' => $validated['usia'], + 'aset_kepemilikan' => $validated['aset_kepemilikan'], + 'bantuan_lain' => $validated['bantuan_lain'], + 'usia' => $validated['usia'], + 'kondisi_rumah' => $validated['kondisi_rumah'], + 'meteran_listrik' => $validated['meteran_listrik'], + 'sumber_air' => $validated['sumber_air'], ]; - $prediction = $this->mlService->getPrediction($predictionData); - if ($prediction) { PrediksiKelayakan::updateOrCreate( ['calon_penerima_id' => $calonPenerima->id], [ - 'probability' => $prediction['probability'], + 'probability' => $prediction['probability'], 'recommendation' => $prediction['recommendation'], + 'kondisi_rumah' => $validated['kondisi_rumah'], + 'meteran_listrik'=> $validated['meteran_listrik'], + 'sumber_air' => $validated['sumber_air'], ] ); } @@ -268,10 +318,7 @@ public function update(Request $request, CalonPenerima $calonPenerima) ->with('success', 'Data calon penerima berhasil diupdate!'); } catch (\Exception $e) { DB::rollBack(); - - return back() - ->withInput() - ->with('error', 'Terjadi kesalahan: ' . $e->getMessage()); + return back()->withInput()->with('error', 'Terjadi kesalahan: ' . $e->getMessage()); } } @@ -288,9 +335,7 @@ public function ajukan(CalonPenerima $calonPenerima) ->with('error', 'Data ini sudah diajukan dan tidak dapat diajukan lagi.'); } - $calonPenerima->update([ - 'tracking_status' => 'terkirim', - ]); + $calonPenerima->update(['tracking_status' => 'terkirim']); return redirect()->route('rt.calon-penerima.index') ->with('success', 'Data berhasil diajukan ke admin kelurahan.'); @@ -300,11 +345,21 @@ public function destroy(CalonPenerima $calonPenerima) { $user = Auth::user(); - // ๐Ÿ”’ RT hanya bisa hapus kalau miliknya + masih draft if ($calonPenerima->user_id !== $user->id || ($calonPenerima->tracking_status ?? 'draft') !== 'draft') { abort(403, 'Data yang sudah diajukan tidak dapat dihapus.'); } + // Hapus foto dari storage + $fotoFields = [ + 'foto_rumah_depan', 'foto_rumah_belakang', 'foto_rumah_kanan', 'foto_rumah_kiri', + 'foto_kk', 'foto_ktp', 'foto_rekening_listrik', 'foto_meteran_air', 'dokumen_pendukung', + ]; + foreach ($fotoFields as $field) { + if ($calonPenerima->$field) { + Storage::disk('public')->delete($calonPenerima->$field); + } + } + $calonPenerima->delete(); return redirect()->route('rt.calon-penerima.index') @@ -316,7 +371,6 @@ private function getPredictionExplanation($calonPenerima): array $positive = []; $negative = []; - // PEKERJAAN if (strtolower($calonPenerima->pekerjaan) === 'tidak bekerja') { $positive[] = 'Tidak bekerja'; } elseif (in_array(strtolower($calonPenerima->pekerjaan), ['buruh harian', 'buruh', 'petani', 'nelayan'])) { @@ -325,7 +379,6 @@ private function getPredictionExplanation($calonPenerima): array $negative[] = 'Memiliki pekerjaan yang relatif lebih stabil'; } - // PENGHASILAN if ($calonPenerima->penghasilan <= 1000000) { $positive[] = 'Penghasilan rendah'; } elseif ($calonPenerima->penghasilan <= 2000000) { @@ -334,7 +387,6 @@ private function getPredictionExplanation($calonPenerima): array $negative[] = 'Penghasilan relatif lebih tinggi'; } - // JUMLAH TANGGUNGAN if ($calonPenerima->jumlah_tanggungan >= 4) { $positive[] = 'Jumlah tanggungan banyak'; } elseif ($calonPenerima->jumlah_tanggungan >= 2) { @@ -343,45 +395,54 @@ private function getPredictionExplanation($calonPenerima): array $negative[] = 'Jumlah tanggungan sedikit'; } - // ASET KEPEMILIKAN $aset = strtolower($calonPenerima->aset_kepemilikan); + if (str_contains($aset, 'mobil')) $negative[] = 'Memiliki aset bernilai tinggi (mobil)'; + if (str_contains($aset, 'motor')) $negative[] = 'Memiliki aset kendaraan bermotor'; + if (str_contains($aset, 'rumah')) $negative[] = 'Memiliki aset rumah'; + if (in_array($aset, ['tidak ada', '-', 'tidak punya'])) $positive[] = 'Tidak memiliki aset berarti'; - if (str_contains($aset, 'mobil')) { - $negative[] = 'Memiliki aset bernilai tinggi (mobil)'; - } - - if (str_contains($aset, 'motor')) { - $negative[] = 'Memiliki aset kendaraan bermotor'; - } - - if (str_contains($aset, 'rumah')) { - $negative[] = 'Memiliki aset rumah'; - } - - if ($aset === 'tidak ada' || $aset === '-' || $aset === 'tidak punya') { - $positive[] = 'Tidak memiliki aset berarti'; - } - - // BANTUAN LAIN if (strtolower($calonPenerima->bantuan_lain) === 'ya') { $negative[] = 'Sudah menerima bantuan lain'; } else { $positive[] = 'Belum menerima bantuan lain'; } - // USIA if ($calonPenerima->usia >= 60) { $positive[] = 'Usia lanjut'; } elseif ($calonPenerima->usia >= 45) { $positive[] = 'Usia cukup rentan'; } - // NARASI PENJELASAN + // Parameter baru + if (strtolower($calonPenerima->kondisi_rumah ?? '') === 'tidak layak') { + $positive[] = 'Kondisi rumah tidak layak huni'; + } elseif (strtolower($calonPenerima->kondisi_rumah ?? '') === 'sedang') { + $positive[] = 'Kondisi rumah sedang'; + } else { + $negative[] = 'Kondisi rumah layak'; + } + + if (($calonPenerima->meteran_listrik ?? '') === '450VA') { + $positive[] = 'Meteran listrik 450VA (daya rendah)'; + } elseif (($calonPenerima->meteran_listrik ?? '') === '900VA') { + $positive[] = 'Meteran listrik 900VA'; + } else { + $negative[] = 'Meteran listrik 1300VA ke atas'; + } + + if (strtolower($calonPenerima->sumber_air ?? '') === 'sungai') { + $positive[] = 'Sumber air dari sungai (kurang layak)'; + } elseif (strtolower($calonPenerima->sumber_air ?? '') === 'sumur') { + $positive[] = 'Sumber air dari sumur'; + } else { + $negative[] = 'Sumber air PDAM (layak)'; + } + $probability = $calonPenerima->prediksiKelayakan->probability ?? 0; $probability = $probability <= 1 ? $probability * 100 : $probability; $probability = number_format($probability, 1); - $summary = "Nilai kelayakan {$probability}% diperoleh berdasarkan data pekerjaan, penghasilan, jumlah tanggungan, aset kepemilikan, bantuan lain, dan usia."; + $summary = "Nilai kelayakan {$probability}% diperoleh berdasarkan data pekerjaan, penghasilan, jumlah tanggungan, aset kepemilikan, bantuan lain, usia, kondisi rumah, meteran listrik, dan sumber air."; if (count($positive) > 0 && count($negative) > 0) { $summary .= " Sistem menilai terdapat beberapa faktor yang mendukung kelayakan, namun ada juga faktor yang mengurangi nilai kelayakan."; @@ -394,7 +455,7 @@ private function getPredictionExplanation($calonPenerima): array return [ 'positive' => $positive, 'negative' => $negative, - 'summary' => $summary, + 'summary' => $summary, ]; } } \ No newline at end of file diff --git a/app/Http/Controllers/Rt/LaporanController.php b/app/Http/Controllers/Rt/LaporanController.php index ea6d59f..0f6551c 100644 --- a/app/Http/Controllers/Rt/LaporanController.php +++ b/app/Http/Controllers/Rt/LaporanController.php @@ -4,7 +4,7 @@ use App\Http\Controllers\Controller; use App\Models\PenerimaFinal; -use App\Models\Rt; +use App\Models\RT; use Illuminate\Http\Request; class LaporanController extends Controller @@ -17,7 +17,7 @@ public function index(Request $request) abort(403, 'Akses ditolak: hanya RT.'); } - $rt = Rt::with('dusun')->find($user->rt_id); + $rt = RT::with('dusun')->find($user->rt_id); if (!$rt) { $laporans = collect(); diff --git a/app/Models/CalonPenerima.php b/app/Models/CalonPenerima.php index 48f05a2..6d3c355 100644 --- a/app/Models/CalonPenerima.php +++ b/app/Models/CalonPenerima.php @@ -10,26 +10,37 @@ class CalonPenerima extends Model use HasFactory; protected $fillable = [ - 'user_id', - 'rt_id', - 'no_kk', - 'nik', - 'nama_lengkap', - 'jenis_kelamin', - 'tempat_lahir', - 'tanggal_lahir', - 'alamat', - 'desa', - 'pekerjaan', - 'penghasilan', - 'jumlah_tanggungan', - 'aset_kepemilikan', - 'bantuan_lain', - 'usia', - 'status_perkawinan', - 'status_verifikasi', - 'tracking_status', // status tracking proses - 'catatan_admin', + 'user_id', + 'rt_id', + 'no_kk', + 'nik', + 'nama_lengkap', + 'jenis_kelamin', + 'tempat_lahir', + 'tanggal_lahir', + 'alamat', + 'desa', + 'pekerjaan', + 'penghasilan', + 'jumlah_tanggungan', + 'aset_kepemilikan', + 'kondisi_rumah', + 'meteran_listrik', + 'sumber_air', + 'bantuan_lain', + 'usia', + 'status_perkawinan', + 'status_verifikasi', + 'catatan_admin', + 'foto_rumah_depan', + 'foto_rumah_belakang', + 'foto_rumah_kanan', + 'foto_rumah_kiri', + 'foto_kk', + 'foto_ktp', + 'foto_rekening_listrik', + 'foto_meteran_air', + 'dokumen_pendukung', ]; protected $casts = [ diff --git a/app/Models/PenerimaFinal.php b/app/Models/PenerimaFinal.php index accafd9..5d11657 100644 --- a/app/Models/PenerimaFinal.php +++ b/app/Models/PenerimaFinal.php @@ -20,6 +20,9 @@ class PenerimaFinal extends Model 'penghasilan', 'jumlah_tanggungan', 'aset_kepemilikan', + 'kondisi_rumah', + 'meteran_listrik', + 'sumber_air', 'bantuan_lain', 'usia', 'probability', @@ -31,10 +34,10 @@ class PenerimaFinal extends Model protected $casts = [ 'tanggal_penetapan' => 'date', - 'jumlah_bantuan' => 'decimal:2', - 'probability' => 'decimal:4', - 'penghasilan' => 'integer', + 'jumlah_bantuan' => 'decimal:2', + 'probability' => 'decimal:4', + 'penghasilan' => 'integer', 'jumlah_tanggungan' => 'integer', - 'usia' => 'integer', + 'usia' => 'integer', ]; } \ No newline at end of file diff --git a/app/Services/MLPredictionService.php b/app/Services/MLPredictionService.php index dbea3ee..547df31 100644 --- a/app/Services/MLPredictionService.php +++ b/app/Services/MLPredictionService.php @@ -3,80 +3,49 @@ namespace App\Services; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Http; class MLPredictionService { - /** - * Dapatkan prediksi dari script Python langsung - */ public function getPrediction(array $data) { try { $payload = [ - 'pekerjaan' => $data['pekerjaan'] ?? '', - 'penghasilan' => (float) ($data['penghasilan'] ?? 0), - 'jumlah_tanggungan' => (int) ($data['jumlah_tanggungan'] ?? 0), - 'aset_kepemilikan' => $data['aset_kepemilikan'] ?? '', - 'bantuan_lain' => $data['bantuan_lain'] ?? '', - 'usia' => (int) ($data['usia'] ?? 0), + 'pekerjaan' => $data['pekerjaan'] ?? '', + 'penghasilan' => (float) ($data['penghasilan'] ?? 0), + 'jumlah_tanggungan' => (int) ($data['jumlah_tanggungan'] ?? 0), + 'aset_kepemilikan' => $data['aset_kepemilikan'] ?? '', + 'bantuan_lain' => $data['bantuan_lain'] ?? '', + 'usia' => (int) ($data['usia'] ?? 0), + 'kondisi_rumah' => $data['kondisi_rumah'] ?? 'Tidak Diketahui', + 'meteran_listrik' => $data['meteran_listrik'] ?? 'Tidak Diketahui', + 'sumber_air' => $data['sumber_air'] ?? 'Tidak Diketahui', ]; - $jsonPayload = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + $apiUrl = env('ML_API_URL', 'https://ianvv.pythonanywhere.com') . '/predict'; - $pythonPath = 'python'; - $scriptPath = base_path('ml/predict.py'); + $response = Http::timeout(30)->post($apiUrl, $payload); - $descriptorspec = [ - 0 => ['pipe', 'r'], // stdin - 1 => ['pipe', 'w'], // stdout - 2 => ['pipe', 'w'], // stderr - ]; - - $process = proc_open( - $pythonPath . ' ' . escapeshellarg($scriptPath), - $descriptorspec, - $pipes, - base_path() - ); - - if (!is_resource($process)) { - Log::error('Gagal menjalankan proses Python ML.'); - return null; - } - - fwrite($pipes[0], $jsonPayload); - fclose($pipes[0]); - - $output = stream_get_contents($pipes[1]); - fclose($pipes[1]); - - $errorOutput = stream_get_contents($pipes[2]); - fclose($pipes[2]); - - $exitCode = proc_close($process); - - if ($exitCode !== 0) { - Log::error('Python ML exit code bukan 0.', [ - 'exit_code' => $exitCode, - 'stderr' => $errorOutput, - 'stdout' => $output, + if (!$response->successful()) { + Log::error('ML API gagal.', [ + 'status' => $response->status(), + 'body' => $response->body(), ]); return null; } - $result = json_decode($output, true); + $result = $response->json(); if (!$result || isset($result['error'])) { Log::error('Hasil prediksi ML tidak valid.', [ - 'output' => $output, - 'stderr' => $errorOutput, + 'output' => $response->body(), 'decoded' => $result, ]); return null; } return [ - 'probability' => $result['probability'] ?? 0, + 'probability' => $result['probability'] ?? 0, 'recommendation' => $result['recommendation'] ?? 'Tidak Layak', ]; } catch (\Throwable $e) { @@ -85,60 +54,30 @@ public function getPrediction(array $data) } } - /** - * Cek apakah script ML bisa dijalankan - */ public function healthCheck() { try { - $pythonPath = 'python'; - $scriptPath = base_path('ml/predict.py'); + $apiUrl = env('ML_API_URL', 'https://ianvv.pythonanywhere.com') . '/predict'; - if (!file_exists($scriptPath)) { - return false; - } - - $testPayload = json_encode([ - 'pekerjaan' => 'buruh', - 'penghasilan' => 500000, - 'jumlah_tanggungan' => 4, - 'aset_kepemilikan' => 'motor', - 'bantuan_lain' => 'tidak', - 'usia' => 50, - ]); - - $descriptorspec = [ - 0 => ['pipe', 'r'], - 1 => ['pipe', 'w'], - 2 => ['pipe', 'w'], + $testPayload = [ + 'pekerjaan' => 'Buruh Harian', + 'penghasilan' => 500000, + 'jumlah_tanggungan' => 4, + 'aset_kepemilikan' => 'Rumah Sederhana', + 'bantuan_lain' => 'tidak', + 'usia' => 50, + 'kondisi_rumah' => 'Tidak Layak', + 'meteran_listrik' => '450VA', + 'sumber_air' => 'Sumur', ]; - $process = proc_open( - $pythonPath . ' ' . escapeshellarg($scriptPath), - $descriptorspec, - $pipes, - base_path() - ); + $response = Http::timeout(10)->post($apiUrl, $testPayload); - if (!is_resource($process)) { + if (!$response->successful()) { return false; } - fwrite($pipes[0], $testPayload); - fclose($pipes[0]); - - $output = stream_get_contents($pipes[1]); - fclose($pipes[1]); - - fclose($pipes[2]); - - $exitCode = proc_close($process); - - if ($exitCode !== 0) { - return false; - } - - $result = json_decode($output, true); + $result = $response->json(); return is_array($result) && isset($result['probability']) && isset($result['recommendation']); } catch (\Throwable $e) { @@ -146,17 +85,12 @@ public function healthCheck() } } - /** - * Prediksi untuk banyak data sekaligus - */ public function getBatchPredictions(array $dataArray) { $results = []; - foreach ($dataArray as $item) { $results[] = $this->getPrediction($item); } - return $results; } } \ No newline at end of file diff --git a/composer.json b/composer.json index 0cf6222..3ddaca0 100644 --- a/composer.json +++ b/composer.json @@ -77,6 +77,9 @@ } }, "config": { + "platform": { + "php": "8.2.0" + }, "optimize-autoloader": true, "preferred-install": "dist", "sort-packages": true, @@ -87,4 +90,4 @@ }, "minimum-stability": "stable", "prefer-stable": true -} +} \ No newline at end of file diff --git a/composer.lock b/composer.lock index 5c8d767..7b93023 100644 --- a/composer.lock +++ b/composer.lock @@ -4,30 +4,30 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "61fce7afd7bfa4be47ac89062b07f583", + "content-hash": "e0c1bd04a3bb8afaef35697676fa0752", "packages": [ { "name": "barryvdh/laravel-dompdf", - "version": "v3.1.1", + "version": "v3.1.2", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-dompdf.git", - "reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d" + "reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d", - "reference": "8e71b99fc53bb8eb77f316c3c452dd74ab7cb25d", + "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/ee3b72b19ccdf57d0243116ecb2b90261344dedc", + "reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc", "shasum": "" }, "require": { "dompdf/dompdf": "^3.0", - "illuminate/support": "^9|^10|^11|^12", + "illuminate/support": "^9|^10|^11|^12|^13.0", "php": "^8.1" }, "require-dev": { "larastan/larastan": "^2.7|^3.0", - "orchestra/testbench": "^7|^8|^9|^10", + "orchestra/testbench": "^7|^8|^9.16|^10|^11.0", "phpro/grumphp": "^2.5", "squizlabs/php_codesniffer": "^3.5" }, @@ -69,7 +69,7 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-dompdf/issues", - "source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.1" + "source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.2" }, "funding": [ { @@ -81,20 +81,20 @@ "type": "github" } ], - "time": "2025-02-13T15:07:54+00:00" + "time": "2026-02-21T08:51:10+00:00" }, { "name": "brick/math", - "version": "0.14.7", + "version": "0.14.8", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "07ff363b16ef8aca9692bba3be9e73fe63f34e50" + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/07ff363b16ef8aca9692bba3be9e73fe63f34e50", - "reference": "07ff363b16ef8aca9692bba3be9e73fe63f34e50", + "url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629", + "reference": "63422359a44b7f06cae63c3b429b59e8efcc0629", "shasum": "" }, "require": { @@ -133,7 +133,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.14.7" + "source": "https://github.com/brick/math/tree/0.14.8" }, "funding": [ { @@ -141,7 +141,7 @@ "type": "github" } ], - "time": "2026-02-07T10:57:35+00:00" + "time": "2026-02-10T14:33:43+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -1301,16 +1301,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.8.0", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "21dc724a0583619cd1652f673303492272778051" + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", - "reference": "21dc724a0583619cd1652f673303492272778051", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/7d0ed42f28e42d61352a7a79de682e5e67fec884", + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884", "shasum": "" }, "require": { @@ -1326,6 +1326,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", + "jshttp/mime-db": "1.54.0.1", "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { @@ -1397,7 +1398,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.8.0" + "source": "https://github.com/guzzle/psr7/tree/2.9.0" }, "funding": [ { @@ -1413,7 +1414,7 @@ "type": "tidelift" } ], - "time": "2025-08-23T21:21:41+00:00" + "time": "2026-03-10T16:41:02+00:00" }, { "name": "guzzlehttp/uri-template", @@ -1503,16 +1504,16 @@ }, { "name": "laravel/framework", - "version": "v12.50.0", + "version": "v12.56.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "174ffed91d794a35a541a5eb7c3785a02a34aaba" + "reference": "dac16d424b59debb2273910dde88eb7050a2a709" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/174ffed91d794a35a541a5eb7c3785a02a34aaba", - "reference": "174ffed91d794a35a541a5eb7c3785a02a34aaba", + "url": "https://api.github.com/repos/laravel/framework/zipball/dac16d424b59debb2273910dde88eb7050a2a709", + "reference": "dac16d424b59debb2273910dde88eb7050a2a709", "shasum": "" }, "require": { @@ -1533,7 +1534,7 @@ "guzzlehttp/uri-template": "^1.0", "laravel/prompts": "^0.3.0", "laravel/serializable-closure": "^1.3|^2.0", - "league/commonmark": "^2.7", + "league/commonmark": "^2.8.1", "league/flysystem": "^3.25.1", "league/flysystem-local": "^3.25.1", "league/uri": "^7.5.1", @@ -1628,7 +1629,7 @@ "orchestra/testbench-core": "^10.9.0", "pda/pheanstalk": "^5.0.6|^7.0.0", "php-http/discovery": "^1.15", - "phpstan/phpstan": "^2.0", + "phpstan/phpstan": "^2.1.41", "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", "predis/predis": "^2.3|^3.0", "resend/resend-php": "^0.10.0|^1.0", @@ -1721,20 +1722,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2026-02-04T18:34:13+00:00" + "time": "2026-03-26T14:51:54+00:00" }, { "name": "laravel/prompts", - "version": "v0.3.12", + "version": "v0.3.16", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "4861ded9003b7f8a158176a0b7666f74ee761be8" + "reference": "11e7d5f93803a2190b00e145142cb00a33d17ad2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/4861ded9003b7f8a158176a0b7666f74ee761be8", - "reference": "4861ded9003b7f8a158176a0b7666f74ee761be8", + "url": "https://api.github.com/repos/laravel/prompts/zipball/11e7d5f93803a2190b00e145142cb00a33d17ad2", + "reference": "11e7d5f93803a2190b00e145142cb00a33d17ad2", "shasum": "" }, "require": { @@ -1778,22 +1779,22 @@ "description": "Add beautiful and user-friendly forms to your command-line applications.", "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.3.12" + "source": "https://github.com/laravel/prompts/tree/v0.3.16" }, - "time": "2026-02-03T06:57:26+00:00" + "time": "2026-03-23T14:35:33+00:00" }, { "name": "laravel/serializable-closure", - "version": "v2.0.9", + "version": "v2.0.11", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "8f631589ab07b7b52fead814965f5a800459cb3e" + "reference": "d1af40ac4a6ccc12bd062a7184f63c9995a63bdd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/8f631589ab07b7b52fead814965f5a800459cb3e", - "reference": "8f631589ab07b7b52fead814965f5a800459cb3e", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/d1af40ac4a6ccc12bd062a7184f63c9995a63bdd", + "reference": "d1af40ac4a6ccc12bd062a7184f63c9995a63bdd", "shasum": "" }, "require": { @@ -1841,20 +1842,20 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2026-02-03T06:55:34+00:00" + "time": "2026-04-07T13:32:18+00:00" }, { "name": "laravel/tinker", - "version": "v2.11.0", + "version": "v2.11.1", "source": { "type": "git", "url": "https://github.com/laravel/tinker.git", - "reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468" + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/tinker/zipball/3d34b97c9a1747a81a3fde90482c092bd8b66468", - "reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468", + "url": "https://api.github.com/repos/laravel/tinker/zipball/c9f80cc835649b5c1842898fb043f8cc098dd741", + "reference": "c9f80cc835649b5c1842898fb043f8cc098dd741", "shasum": "" }, "require": { @@ -1905,22 +1906,22 @@ ], "support": { "issues": "https://github.com/laravel/tinker/issues", - "source": "https://github.com/laravel/tinker/tree/v2.11.0" + "source": "https://github.com/laravel/tinker/tree/v2.11.1" }, - "time": "2025-12-19T19:16:45+00:00" + "time": "2026-02-06T14:12:35+00:00" }, { "name": "league/commonmark", - "version": "2.8.0", + "version": "2.8.2", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb" + "reference": "59fb075d2101740c337c7216e3f32b36c204218b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/4efa10c1e56488e658d10adf7b7b7dcd19940bfb", - "reference": "4efa10c1e56488e658d10adf7b7b7dcd19940bfb", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/59fb075d2101740c337c7216e3f32b36c204218b", + "reference": "59fb075d2101740c337c7216e3f32b36c204218b", "shasum": "" }, "require": { @@ -1945,9 +1946,9 @@ "phpstan/phpstan": "^1.8.2", "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", "scrutinizer/ocular": "^1.8.1", - "symfony/finder": "^5.3 | ^6.0 | ^7.0", - "symfony/process": "^5.4 | ^6.0 | ^7.0", - "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", + "symfony/finder": "^5.3 | ^6.0 | ^7.0 || ^8.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0 || ^8.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0 || ^8.0", "unleashedtech/php-coding-standard": "^3.1.1", "vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0" }, @@ -2014,7 +2015,7 @@ "type": "tidelift" } ], - "time": "2025-11-26T21:48:24+00:00" + "time": "2026-03-19T13:16:38+00:00" }, { "name": "league/config", @@ -2100,16 +2101,16 @@ }, { "name": "league/flysystem", - "version": "3.31.0", + "version": "3.33.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "1717e0b3642b0df65ecb0cc89cdd99fa840672ff" + "reference": "570b8871e0ce693764434b29154c54b434905350" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/1717e0b3642b0df65ecb0cc89cdd99fa840672ff", - "reference": "1717e0b3642b0df65ecb0cc89cdd99fa840672ff", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/570b8871e0ce693764434b29154c54b434905350", + "reference": "570b8871e0ce693764434b29154c54b434905350", "shasum": "" }, "require": { @@ -2177,9 +2178,9 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.31.0" + "source": "https://github.com/thephpleague/flysystem/tree/3.33.0" }, - "time": "2026-01-23T15:38:47+00:00" + "time": "2026-03-25T07:59:30+00:00" }, { "name": "league/flysystem-local", @@ -2288,20 +2289,20 @@ }, { "name": "league/uri", - "version": "7.8.0", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/thephpleague/uri.git", - "reference": "4436c6ec8d458e4244448b069cc572d088230b76" + "reference": "08cf38e3924d4f56238125547b5720496fac8fd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/4436c6ec8d458e4244448b069cc572d088230b76", - "reference": "4436c6ec8d458e4244448b069cc572d088230b76", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/08cf38e3924d4f56238125547b5720496fac8fd4", + "reference": "08cf38e3924d4f56238125547b5720496fac8fd4", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.8", + "league/uri-interfaces": "^7.8.1", "php": "^8.1", "psr/http-factory": "^1" }, @@ -2374,7 +2375,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.8.0" + "source": "https://github.com/thephpleague/uri/tree/7.8.1" }, "funding": [ { @@ -2382,20 +2383,20 @@ "type": "github" } ], - "time": "2026-01-14T17:24:56+00:00" + "time": "2026-03-15T20:22:25+00:00" }, { "name": "league/uri-interfaces", - "version": "7.8.0", + "version": "7.8.1", "source": { "type": "git", "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4" + "reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/c5c5cd056110fc8afaba29fa6b72a43ced42acd4", - "reference": "c5c5cd056110fc8afaba29fa6b72a43ced42acd4", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/85d5c77c5d6d3af6c54db4a78246364908f3c928", + "reference": "85d5c77c5d6d3af6c54db4a78246364908f3c928", "shasum": "" }, "require": { @@ -2458,7 +2459,7 @@ "docs": "https://uri.thephpleague.com", "forum": "https://thephpleague.slack.com", "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.0" + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.8.1" }, "funding": [ { @@ -2466,33 +2467,33 @@ "type": "github" } ], - "time": "2026-01-15T06:54:53+00:00" + "time": "2026-03-08T20:05:35+00:00" }, { "name": "maatwebsite/excel", - "version": "3.1.67", + "version": "3.1.68", "source": { "type": "git", "url": "https://github.com/SpartnerNL/Laravel-Excel.git", - "reference": "e508e34a502a3acc3329b464dad257378a7edb4d" + "reference": "1854739267d81d38eae7d8c623caf523f30f256b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/e508e34a502a3acc3329b464dad257378a7edb4d", - "reference": "e508e34a502a3acc3329b464dad257378a7edb4d", + "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/1854739267d81d38eae7d8c623caf523f30f256b", + "reference": "1854739267d81d38eae7d8c623caf523f30f256b", "shasum": "" }, "require": { "composer/semver": "^3.3", "ext-json": "*", - "illuminate/support": "5.8.*||^6.0||^7.0||^8.0||^9.0||^10.0||^11.0||^12.0", + "illuminate/support": "5.8.*||^6.0||^7.0||^8.0||^9.0||^10.0||^11.0||^12.0||^13.0", "php": "^7.0||^8.0", "phpoffice/phpspreadsheet": "^1.30.0", "psr/simple-cache": "^1.0||^2.0||^3.0" }, "require-dev": { - "laravel/scout": "^7.0||^8.0||^9.0||^10.0", - "orchestra/testbench": "^6.0||^7.0||^8.0||^9.0||^10.0", + "laravel/scout": "^7.0||^8.0||^9.0||^10.0||^11.0", + "orchestra/testbench": "^6.0||^7.0||^8.0||^9.0||^10.0||^11.0", "predis/predis": "^1.1" }, "type": "library", @@ -2535,7 +2536,7 @@ ], "support": { "issues": "https://github.com/SpartnerNL/Laravel-Excel/issues", - "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.67" + "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.68" }, "funding": [ { @@ -2547,35 +2548,35 @@ "type": "github" } ], - "time": "2025-08-26T09:13:16+00:00" + "time": "2026-03-17T20:51:10+00:00" }, { "name": "maennchen/zipstream-php", - "version": "3.2.1", + "version": "3.1.2", "source": { "type": "git", "url": "https://github.com/maennchen/ZipStream-PHP.git", - "reference": "682f1098a8fddbaf43edac2306a691c7ad508ec5" + "reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/682f1098a8fddbaf43edac2306a691c7ad508ec5", - "reference": "682f1098a8fddbaf43edac2306a691c7ad508ec5", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/aeadcf5c412332eb426c0f9b4485f6accba2a99f", + "reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f", "shasum": "" }, "require": { "ext-mbstring": "*", "ext-zlib": "*", - "php-64bit": "^8.3" + "php-64bit": "^8.2" }, "require-dev": { "brianium/paratest": "^7.7", "ext-zip": "*", - "friendsofphp/php-cs-fixer": "^3.86", + "friendsofphp/php-cs-fixer": "^3.16", "guzzlehttp/guzzle": "^7.5", "mikey179/vfsstream": "^1.6", "php-coveralls/php-coveralls": "^2.5", - "phpunit/phpunit": "^12.0", + "phpunit/phpunit": "^11.0", "vimeo/psalm": "^6.0" }, "suggest": { @@ -2617,7 +2618,7 @@ ], "support": { "issues": "https://github.com/maennchen/ZipStream-PHP/issues", - "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.2.1" + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.2" }, "funding": [ { @@ -2625,7 +2626,7 @@ "type": "github" } ], - "time": "2025-12-10T09:58:31+00:00" + "time": "2025-01-27T12:07:53+00:00" }, { "name": "markbaker/complex", @@ -2906,16 +2907,16 @@ }, { "name": "nesbot/carbon", - "version": "3.11.1", + "version": "3.11.4", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "f438fcc98f92babee98381d399c65336f3a3827f" + "reference": "e890471a3494740f7d9326d72ce6a8c559ffee60" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/f438fcc98f92babee98381d399c65336f3a3827f", - "reference": "f438fcc98f92babee98381d399c65336f3a3827f", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/e890471a3494740f7d9326d72ce6a8c559ffee60", + "reference": "e890471a3494740f7d9326d72ce6a8c559ffee60", "shasum": "" }, "require": { @@ -3007,20 +3008,20 @@ "type": "tidelift" } ], - "time": "2026-01-29T09:26:29+00:00" + "time": "2026-04-07T09:57:54+00:00" }, { "name": "nette/schema", - "version": "v1.3.3", + "version": "v1.3.5", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004" + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004", - "reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004", + "url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002", + "reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002", "shasum": "" }, "require": { @@ -3028,8 +3029,10 @@ "php": "8.1 - 8.5" }, "require-dev": { - "nette/tester": "^2.5.2", - "phpstan/phpstan-nette": "^2.0@stable", + "nette/phpstan-rules": "^1.0", + "nette/tester": "^2.6", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1.39@stable", "tracy/tracy": "^2.8" }, "type": "library", @@ -3070,22 +3073,22 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.3.3" + "source": "https://github.com/nette/schema/tree/v1.3.5" }, - "time": "2025-10-30T22:57:59+00:00" + "time": "2026-02-23T03:47:12+00:00" }, { "name": "nette/utils", - "version": "v4.1.2", + "version": "v4.1.3", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5" + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/f76b5dc3d6c6d3043c8d937df2698515b99cbaf5", - "reference": "f76b5dc3d6c6d3043c8d937df2698515b99cbaf5", + "url": "https://api.github.com/repos/nette/utils/zipball/bb3ea637e3d131d72acc033cfc2746ee893349fe", + "reference": "bb3ea637e3d131d72acc033cfc2746ee893349fe", "shasum": "" }, "require": { @@ -3097,8 +3100,10 @@ }, "require-dev": { "jetbrains/phpstorm-attributes": "^1.2", + "nette/phpstan-rules": "^1.0", "nette/tester": "^2.5", - "phpstan/phpstan": "^2.0@stable", + "phpstan/extension-installer": "^1.4@stable", + "phpstan/phpstan": "^2.1@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -3159,9 +3164,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.1.2" + "source": "https://github.com/nette/utils/tree/v4.1.3" }, - "time": "2026-02-03T17:21:09+00:00" + "time": "2026-02-13T03:05:33+00:00" }, { "name": "nikic/php-parser", @@ -3223,31 +3228,31 @@ }, { "name": "nunomaduro/termwind", - "version": "v2.3.3", + "version": "v2.4.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/termwind.git", - "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017" + "reference": "712a31b768f5daea284c2169a7d227031001b9a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/6fb2a640ff502caace8e05fd7be3b503a7e1c017", - "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/712a31b768f5daea284c2169a7d227031001b9a8", + "reference": "712a31b768f5daea284c2169a7d227031001b9a8", "shasum": "" }, "require": { "ext-mbstring": "*", "php": "^8.2", - "symfony/console": "^7.3.6" + "symfony/console": "^7.4.4 || ^8.0.4" }, "require-dev": { - "illuminate/console": "^11.46.1", - "laravel/pint": "^1.25.1", + "illuminate/console": "^11.47.0", + "laravel/pint": "^1.27.1", "mockery/mockery": "^1.6.12", - "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.1.3", + "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.3.2", "phpstan/phpstan": "^1.12.32", "phpstan/phpstan-strict-rules": "^1.6.2", - "symfony/var-dumper": "^7.3.5", + "symfony/var-dumper": "^7.3.5 || ^8.0.4", "thecodingmachine/phpstan-strict-rules": "^1.0.0" }, "type": "library", @@ -3279,7 +3284,7 @@ "email": "enunomaduro@gmail.com" } ], - "description": "Its like Tailwind CSS, but for the console.", + "description": "It's like Tailwind CSS, but for the console.", "keywords": [ "cli", "console", @@ -3290,7 +3295,7 @@ ], "support": { "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v2.3.3" + "source": "https://github.com/nunomaduro/termwind/tree/v2.4.0" }, "funding": [ { @@ -3306,7 +3311,7 @@ "type": "github" } ], - "time": "2025-11-20T02:34:59+00:00" + "time": "2026-02-16T23:10:27+00:00" }, { "name": "phpoffice/phpspreadsheet", @@ -3905,16 +3910,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.19", + "version": "v0.12.22", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "a4f766e5c5b6773d8399711019bb7d90875a50ee" + "reference": "3be75d5b9244936dd4ac62ade2bfb004d13acf0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/a4f766e5c5b6773d8399711019bb7d90875a50ee", - "reference": "a4f766e5c5b6773d8399711019bb7d90875a50ee", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/3be75d5b9244936dd4ac62ade2bfb004d13acf0f", + "reference": "3be75d5b9244936dd4ac62ade2bfb004d13acf0f", "shasum": "" }, "require": { @@ -3978,9 +3983,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.19" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.22" }, - "time": "2026-01-30T17:33:13+00:00" + "time": "2026-03-22T23:03:24+00:00" }, { "name": "ralouphie/getallheaders", @@ -4262,16 +4267,16 @@ }, { "name": "symfony/clock", - "version": "v7.4.0", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "9169f24776edde469914c1e7a1442a50f7a4e110" + "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110", - "reference": "9169f24776edde469914c1e7a1442a50f7a4e110", + "url": "https://api.github.com/repos/symfony/clock/zipball/674fa3b98e21531dd040e613479f5f6fa8f32111", + "reference": "674fa3b98e21531dd040e613479f5f6fa8f32111", "shasum": "" }, "require": { @@ -4316,7 +4321,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v7.4.0" + "source": "https://github.com/symfony/clock/tree/v7.4.8" }, "funding": [ { @@ -4336,20 +4341,20 @@ "type": "tidelift" } ], - "time": "2025-11-12T15:39:26+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/console", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894" + "reference": "1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/41e38717ac1dd7a46b6bda7d6a82af2d98a78894", - "reference": "41e38717ac1dd7a46b6bda7d6a82af2d98a78894", + "url": "https://api.github.com/repos/symfony/console/zipball/1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707", + "reference": "1e92e39c51f95b88e3d66fa2d9f06d1fb45dd707", "shasum": "" }, "require": { @@ -4414,7 +4419,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.4" + "source": "https://github.com/symfony/console/tree/v7.4.8" }, "funding": [ { @@ -4434,20 +4439,20 @@ "type": "tidelift" } ], - "time": "2026-01-13T11:36:38+00:00" + "time": "2026-03-30T13:54:39+00:00" }, { "name": "symfony/css-selector", - "version": "v7.4.0", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135" + "reference": "b055f228a4178a1d6774909903905e3475f3eac8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/ab862f478513e7ca2fe9ec117a6f01a8da6e1135", - "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/b055f228a4178a1d6774909903905e3475f3eac8", + "reference": "b055f228a4178a1d6774909903905e3475f3eac8", "shasum": "" }, "require": { @@ -4483,7 +4488,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.4.0" + "source": "https://github.com/symfony/css-selector/tree/v7.4.8" }, "funding": [ { @@ -4503,7 +4508,7 @@ "type": "tidelift" } ], - "time": "2025-10-30T13:39:42+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/deprecation-contracts", @@ -4574,16 +4579,16 @@ }, { "name": "symfony/error-handler", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "8da531f364ddfee53e36092a7eebbbd0b775f6b8" + "reference": "8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/8da531f364ddfee53e36092a7eebbbd0b775f6b8", - "reference": "8da531f364ddfee53e36092a7eebbbd0b775f6b8", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa", + "reference": "8dd79d8af777ee6cba2fd4d98da6ffb839f3c0fa", "shasum": "" }, "require": { @@ -4632,7 +4637,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v7.4.4" + "source": "https://github.com/symfony/error-handler/tree/v7.4.8" }, "funding": [ { @@ -4652,20 +4657,20 @@ "type": "tidelift" } ], - "time": "2026-01-20T16:42:42+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "dc2c0eba1af673e736bb851d747d266108aea746" + "reference": "f57b899fa736fd71121168ef268f23c206083f0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dc2c0eba1af673e736bb851d747d266108aea746", - "reference": "dc2c0eba1af673e736bb851d747d266108aea746", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f57b899fa736fd71121168ef268f23c206083f0a", + "reference": "f57b899fa736fd71121168ef268f23c206083f0a", "shasum": "" }, "require": { @@ -4717,7 +4722,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.4" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.8" }, "funding": [ { @@ -4737,7 +4742,7 @@ "type": "tidelift" } ], - "time": "2026-01-05T11:45:34+00:00" + "time": "2026-03-30T13:54:39+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -4817,16 +4822,16 @@ }, { "name": "symfony/finder", - "version": "v7.4.5", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb" + "reference": "e0be088d22278583a82da281886e8c3592fbf149" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", - "reference": "ad4daa7c38668dcb031e63bc99ea9bd42196a2cb", + "url": "https://api.github.com/repos/symfony/finder/zipball/e0be088d22278583a82da281886e8c3592fbf149", + "reference": "e0be088d22278583a82da281886e8c3592fbf149", "shasum": "" }, "require": { @@ -4861,7 +4866,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.5" + "source": "https://github.com/symfony/finder/tree/v7.4.8" }, "funding": [ { @@ -4881,20 +4886,20 @@ "type": "tidelift" } ], - "time": "2026-01-26T15:07:59+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.4.5", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "446d0db2b1f21575f1284b74533e425096abdfb6" + "reference": "9381209597ec66c25be154cbf2289076e64d1eab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/446d0db2b1f21575f1284b74533e425096abdfb6", - "reference": "446d0db2b1f21575f1284b74533e425096abdfb6", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9381209597ec66c25be154cbf2289076e64d1eab", + "reference": "9381209597ec66c25be154cbf2289076e64d1eab", "shasum": "" }, "require": { @@ -4943,7 +4948,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v7.4.5" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.8" }, "funding": [ { @@ -4963,20 +4968,20 @@ "type": "tidelift" } ], - "time": "2026-01-27T16:16:02+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.4.5", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "229eda477017f92bd2ce7615d06222ec0c19e82a" + "reference": "017e76ad089bac281553389269e259e155935e1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/229eda477017f92bd2ce7615d06222ec0c19e82a", - "reference": "229eda477017f92bd2ce7615d06222ec0c19e82a", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/017e76ad089bac281553389269e259e155935e1a", + "reference": "017e76ad089bac281553389269e259e155935e1a", "shasum": "" }, "require": { @@ -5018,7 +5023,7 @@ "symfony/config": "^6.4|^7.0|^8.0", "symfony/console": "^6.4|^7.0|^8.0", "symfony/css-selector": "^6.4|^7.0|^8.0", - "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4.1|^7.0.1|^8.0", "symfony/dom-crawler": "^6.4|^7.0|^8.0", "symfony/expression-language": "^6.4|^7.0|^8.0", "symfony/finder": "^6.4|^7.0|^8.0", @@ -5062,7 +5067,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v7.4.5" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.8" }, "funding": [ { @@ -5082,20 +5087,20 @@ "type": "tidelift" } ], - "time": "2026-01-28T10:33:42+00:00" + "time": "2026-03-31T20:57:01+00:00" }, { "name": "symfony/mailer", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "7b750074c40c694ceb34cb926d6dffee231c5cd6" + "reference": "f6ea532250b476bfc1b56699b388a1bdbf168f62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/7b750074c40c694ceb34cb926d6dffee231c5cd6", - "reference": "7b750074c40c694ceb34cb926d6dffee231c5cd6", + "url": "https://api.github.com/repos/symfony/mailer/zipball/f6ea532250b476bfc1b56699b388a1bdbf168f62", + "reference": "f6ea532250b476bfc1b56699b388a1bdbf168f62", "shasum": "" }, "require": { @@ -5146,7 +5151,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.4.4" + "source": "https://github.com/symfony/mailer/tree/v7.4.8" }, "funding": [ { @@ -5166,20 +5171,20 @@ "type": "tidelift" } ], - "time": "2026-01-08T08:25:11+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/mime", - "version": "v7.4.5", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "b18c7e6e9eee1e19958138df10412f3c4c316148" + "reference": "6df02f99998081032da3407a8d6c4e1dcb5d4379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/b18c7e6e9eee1e19958138df10412f3c4c316148", - "reference": "b18c7e6e9eee1e19958138df10412f3c4c316148", + "url": "https://api.github.com/repos/symfony/mime/zipball/6df02f99998081032da3407a8d6c4e1dcb5d4379", + "reference": "6df02f99998081032da3407a8d6c4e1dcb5d4379", "shasum": "" }, "require": { @@ -5190,7 +5195,7 @@ }, "conflict": { "egulias/email-validator": "~3.0.0", - "phpdocumentor/reflection-docblock": "<5.2|>=6", + "phpdocumentor/reflection-docblock": "<5.2|>=7", "phpdocumentor/type-resolver": "<1.5.1", "symfony/mailer": "<6.4", "symfony/serializer": "<6.4.3|>7.0,<7.0.3" @@ -5198,7 +5203,7 @@ "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", - "phpdocumentor/reflection-docblock": "^5.2", + "phpdocumentor/reflection-docblock": "^5.2|^6.0", "symfony/dependency-injection": "^6.4|^7.0|^8.0", "symfony/process": "^6.4|^7.0|^8.0", "symfony/property-access": "^6.4|^7.0|^8.0", @@ -5235,7 +5240,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.4.5" + "source": "https://github.com/symfony/mime/tree/v7.4.8" }, "funding": [ { @@ -5255,7 +5260,7 @@ "type": "tidelift" } ], - "time": "2026-01-27T08:59:58+00:00" + "time": "2026-03-30T14:11:46+00:00" }, { "name": "symfony/polyfill-ctype", @@ -6088,16 +6093,16 @@ }, { "name": "symfony/process", - "version": "v7.4.5", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "608476f4604102976d687c483ac63a79ba18cc97" + "reference": "60f19cd3badc8de688421e21e4305eba50f8089a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/608476f4604102976d687c483ac63a79ba18cc97", - "reference": "608476f4604102976d687c483ac63a79ba18cc97", + "url": "https://api.github.com/repos/symfony/process/zipball/60f19cd3badc8de688421e21e4305eba50f8089a", + "reference": "60f19cd3badc8de688421e21e4305eba50f8089a", "shasum": "" }, "require": { @@ -6129,7 +6134,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.4.5" + "source": "https://github.com/symfony/process/tree/v7.4.8" }, "funding": [ { @@ -6149,20 +6154,20 @@ "type": "tidelift" } ], - "time": "2026-01-26T15:07:59+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/routing", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "0798827fe2c79caeed41d70b680c2c3507d10147" + "reference": "9608de9873ec86e754fb6c0a0fa7e5f1a960eb6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/0798827fe2c79caeed41d70b680c2c3507d10147", - "reference": "0798827fe2c79caeed41d70b680c2c3507d10147", + "url": "https://api.github.com/repos/symfony/routing/zipball/9608de9873ec86e754fb6c0a0fa7e5f1a960eb6b", + "reference": "9608de9873ec86e754fb6c0a0fa7e5f1a960eb6b", "shasum": "" }, "require": { @@ -6214,7 +6219,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.4.4" + "source": "https://github.com/symfony/routing/tree/v7.4.8" }, "funding": [ { @@ -6234,7 +6239,7 @@ "type": "tidelift" } ], - "time": "2026-01-12T12:19:02+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/service-contracts", @@ -6325,16 +6330,16 @@ }, { "name": "symfony/string", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f" + "reference": "114ac57257d75df748eda23dd003878080b8e688" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/1c4b10461bf2ec27537b5f36105337262f5f5d6f", - "reference": "1c4b10461bf2ec27537b5f36105337262f5f5d6f", + "url": "https://api.github.com/repos/symfony/string/zipball/114ac57257d75df748eda23dd003878080b8e688", + "reference": "114ac57257d75df748eda23dd003878080b8e688", "shasum": "" }, "require": { @@ -6392,7 +6397,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.4.4" + "source": "https://github.com/symfony/string/tree/v7.4.8" }, "funding": [ { @@ -6412,20 +6417,20 @@ "type": "tidelift" } ], - "time": "2026-01-12T10:54:30+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/translation", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "bfde13711f53f549e73b06d27b35a55207528877" + "reference": "33600f8489485425bfcddd0d983391038d3422e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/bfde13711f53f549e73b06d27b35a55207528877", - "reference": "bfde13711f53f549e73b06d27b35a55207528877", + "url": "https://api.github.com/repos/symfony/translation/zipball/33600f8489485425bfcddd0d983391038d3422e7", + "reference": "33600f8489485425bfcddd0d983391038d3422e7", "shasum": "" }, "require": { @@ -6492,7 +6497,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.4.4" + "source": "https://github.com/symfony/translation/tree/v7.4.8" }, "funding": [ { @@ -6512,7 +6517,7 @@ "type": "tidelift" } ], - "time": "2026-01-13T10:40:19+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/translation-contracts", @@ -6598,16 +6603,16 @@ }, { "name": "symfony/uid", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36" + "reference": "6883ebdf7bf6a12b37519dbc0df62b0222401b56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/7719ce8aba76be93dfe249192f1fbfa52c588e36", - "reference": "7719ce8aba76be93dfe249192f1fbfa52c588e36", + "url": "https://api.github.com/repos/symfony/uid/zipball/6883ebdf7bf6a12b37519dbc0df62b0222401b56", + "reference": "6883ebdf7bf6a12b37519dbc0df62b0222401b56", "shasum": "" }, "require": { @@ -6652,7 +6657,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v7.4.4" + "source": "https://github.com/symfony/uid/tree/v7.4.8" }, "funding": [ { @@ -6672,20 +6677,20 @@ "type": "tidelift" } ], - "time": "2026-01-03T23:30:35+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "symfony/var-dumper", - "version": "v7.4.4", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "0e4769b46a0c3c62390d124635ce59f66874b282" + "reference": "9510c3966f749a1d1ff0059e1eabef6cc621e7fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/0e4769b46a0c3c62390d124635ce59f66874b282", - "reference": "0e4769b46a0c3c62390d124635ce59f66874b282", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9510c3966f749a1d1ff0059e1eabef6cc621e7fd", + "reference": "9510c3966f749a1d1ff0059e1eabef6cc621e7fd", "shasum": "" }, "require": { @@ -6739,7 +6744,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.4.4" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.8" }, "funding": [ { @@ -6759,7 +6764,7 @@ "type": "tidelift" } ], - "time": "2026-01-01T22:13:48+00:00" + "time": "2026-03-30T13:44:50+00:00" }, { "name": "thecodingmachine/safe", @@ -7121,38 +7126,39 @@ "packages-dev": [ { "name": "barryvdh/laravel-ide-helper", - "version": "v3.6.1", + "version": "v3.7.0", "source": { "type": "git", "url": "https://github.com/barryvdh/laravel-ide-helper.git", - "reference": "b106f7ee85f263c4f103eca49e7bf3862c2e5e75" + "reference": "ad7e37676f1ff985d55ef1b6b96a0c0a40f2609a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/b106f7ee85f263c4f103eca49e7bf3862c2e5e75", - "reference": "b106f7ee85f263c4f103eca49e7bf3862c2e5e75", + "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/ad7e37676f1ff985d55ef1b6b96a0c0a40f2609a", + "reference": "ad7e37676f1ff985d55ef1b6b96a0c0a40f2609a", "shasum": "" }, "require": { "barryvdh/reflection-docblock": "^2.4", "composer/class-map-generator": "^1.0", "ext-json": "*", - "illuminate/console": "^11.15 || ^12", - "illuminate/database": "^11.15 || ^12", - "illuminate/filesystem": "^11.15 || ^12", - "illuminate/support": "^11.15 || ^12", + "illuminate/console": "^11.15 || ^12 || ^13.0", + "illuminate/database": "^11.15 || ^12 || ^13.0", + "illuminate/filesystem": "^11.15 || ^12 || ^13.0", + "illuminate/support": "^11.15 || ^12 || ^13.0", "php": "^8.2" }, "require-dev": { "ext-pdo_sqlite": "*", "friendsofphp/php-cs-fixer": "^3", - "illuminate/config": "^11.15 || ^12", - "illuminate/view": "^11.15 || ^12", + "illuminate/config": "^11.15 || ^12 || ^13.0", + "illuminate/view": "^11.15 || ^12 || ^13.0", + "larastan/larastan": "^3.1", "mockery/mockery": "^1.4", - "orchestra/testbench": "^9.2 || ^10", - "phpunit/phpunit": "^10.5 || ^11.5.3", + "orchestra/testbench": "^9.2 || ^10 || ^11.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5 || ^11.5.3 || ^12.5.12", "spatie/phpunit-snapshot-assertions": "^4 || ^5", - "vimeo/psalm": "^5.4", "vlucas/phpdotenv": "^5" }, "suggest": { @@ -7166,7 +7172,7 @@ ] }, "branch-alias": { - "dev-master": "3.5-dev" + "dev-master": "3.6-dev" } }, "autoload": { @@ -7199,7 +7205,7 @@ ], "support": { "issues": "https://github.com/barryvdh/laravel-ide-helper/issues", - "source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.6.1" + "source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.7.0" }, "funding": [ { @@ -7211,20 +7217,20 @@ "type": "github" } ], - "time": "2025-12-10T09:11:07+00:00" + "time": "2026-03-17T14:12:51+00:00" }, { "name": "barryvdh/reflection-docblock", - "version": "v2.4.0", + "version": "v2.4.1", "source": { "type": "git", "url": "https://github.com/barryvdh/ReflectionDocBlock.git", - "reference": "d103774cbe7e94ddee7e4870f97f727b43fe7201" + "reference": "4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/d103774cbe7e94ddee7e4870f97f727b43fe7201", - "reference": "d103774cbe7e94ddee7e4870f97f727b43fe7201", + "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b", + "reference": "4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b", "shasum": "" }, "require": { @@ -7261,22 +7267,22 @@ } ], "support": { - "source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.4.0" + "source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.4.1" }, - "time": "2025-07-17T06:07:30+00:00" + "time": "2026-03-05T20:09:01+00:00" }, { "name": "composer/class-map-generator", - "version": "1.7.1", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/composer/class-map-generator.git", - "reference": "8f5fa3cc214230e71f54924bd0197a3bcc705eb1" + "reference": "6a9c2f0970022ab00dc58c07d0685dd712f2231b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/class-map-generator/zipball/8f5fa3cc214230e71f54924bd0197a3bcc705eb1", - "reference": "8f5fa3cc214230e71f54924bd0197a3bcc705eb1", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/6a9c2f0970022ab00dc58c07d0685dd712f2231b", + "reference": "6a9c2f0970022ab00dc58c07d0685dd712f2231b", "shasum": "" }, "require": { @@ -7320,7 +7326,7 @@ ], "support": { "issues": "https://github.com/composer/class-map-generator/issues", - "source": "https://github.com/composer/class-map-generator/tree/1.7.1" + "source": "https://github.com/composer/class-map-generator/tree/1.7.2" }, "funding": [ { @@ -7332,7 +7338,7 @@ "type": "github" } ], - "time": "2025-12-29T13:15:25+00:00" + "time": "2026-03-30T15:36:56+00:00" }, { "name": "fakerphp/faker", @@ -7521,29 +7527,29 @@ }, { "name": "laravel/breeze", - "version": "v2.3.8", + "version": "v2.4.1", "source": { "type": "git", "url": "https://github.com/laravel/breeze.git", - "reference": "1a29c5792818bd4cddf70b5f743a227e02fbcfcd" + "reference": "28cefeaf6af20177ddf5cc7b93e87e4ad79d533f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/breeze/zipball/1a29c5792818bd4cddf70b5f743a227e02fbcfcd", - "reference": "1a29c5792818bd4cddf70b5f743a227e02fbcfcd", + "url": "https://api.github.com/repos/laravel/breeze/zipball/28cefeaf6af20177ddf5cc7b93e87e4ad79d533f", + "reference": "28cefeaf6af20177ddf5cc7b93e87e4ad79d533f", "shasum": "" }, "require": { - "illuminate/console": "^11.0|^12.0", - "illuminate/filesystem": "^11.0|^12.0", - "illuminate/support": "^11.0|^12.0", - "illuminate/validation": "^11.0|^12.0", + "illuminate/console": "^11.0|^12.0|^13.0", + "illuminate/filesystem": "^11.0|^12.0|^13.0", + "illuminate/support": "^11.0|^12.0|^13.0", + "illuminate/validation": "^11.0|^12.0|^13.0", "php": "^8.2.0", - "symfony/console": "^7.0" + "symfony/console": "^7.0|^8.0" }, "require-dev": { - "laravel/framework": "^11.0|^12.0", - "orchestra/testbench-core": "^9.0|^10.0", + "laravel/framework": "^11.0|^12.0|^13.0", + "orchestra/testbench-core": "^9.0|^10.0|^11.0", "phpstan/phpstan": "^2.0" }, "type": "library", @@ -7578,20 +7584,20 @@ "issues": "https://github.com/laravel/breeze/issues", "source": "https://github.com/laravel/breeze" }, - "time": "2025-07-18T18:49:59+00:00" + "time": "2026-03-10T19:59:01+00:00" }, { "name": "laravel/pail", - "version": "v1.2.5", + "version": "v1.2.6", "source": { "type": "git", "url": "https://github.com/laravel/pail.git", - "reference": "fdb73f5eacf03db576c710d5a00101ba185f2254" + "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pail/zipball/fdb73f5eacf03db576c710d5a00101ba185f2254", - "reference": "fdb73f5eacf03db576c710d5a00101ba185f2254", + "url": "https://api.github.com/repos/laravel/pail/zipball/aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", + "reference": "aa71a01c309e7f66bc2ec4fb1a59291b82eb4abf", "shasum": "" }, "require": { @@ -7658,20 +7664,20 @@ "issues": "https://github.com/laravel/pail/issues", "source": "https://github.com/laravel/pail" }, - "time": "2026-02-04T15:10:32+00:00" + "time": "2026-02-09T13:44:54+00:00" }, { "name": "laravel/pint", - "version": "v1.27.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90" + "reference": "bdec963f53172c5e36330f3a400604c69bf02d39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/c67b4195b75491e4dfc6b00b1c78b68d86f54c90", - "reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90", + "url": "https://api.github.com/repos/laravel/pint/zipball/bdec963f53172c5e36330f3a400604c69bf02d39", + "reference": "bdec963f53172c5e36330f3a400604c69bf02d39", "shasum": "" }, "require": { @@ -7682,13 +7688,14 @@ "php": "^8.2.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.92.4", - "illuminate/view": "^12.44.0", - "larastan/larastan": "^3.8.1", - "laravel-zero/framework": "^12.0.4", + "friendsofphp/php-cs-fixer": "^3.94.2", + "illuminate/view": "^12.54.1", + "larastan/larastan": "^3.9.3", + "laravel-zero/framework": "^12.0.5", "mockery/mockery": "^1.6.12", - "nunomaduro/termwind": "^2.3.3", - "pestphp/pest": "^3.8.4" + "nunomaduro/termwind": "^2.4.0", + "pestphp/pest": "^3.8.6", + "shipfastlabs/agent-detector": "^1.1.0" }, "bin": [ "builds/pint" @@ -7725,32 +7732,32 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2026-01-05T16:49:17+00:00" + "time": "2026-03-12T15:51:39+00:00" }, { "name": "laravel/sail", - "version": "v1.52.0", + "version": "v1.56.0", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3" + "reference": "f43426bb42a1cb7a51a3861d9138063e54766d28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/64ac7d8abb2dbcf2b76e61289451bae79066b0b3", - "reference": "64ac7d8abb2dbcf2b76e61289451bae79066b0b3", + "url": "https://api.github.com/repos/laravel/sail/zipball/f43426bb42a1cb7a51a3861d9138063e54766d28", + "reference": "f43426bb42a1cb7a51a3861d9138063e54766d28", "shasum": "" }, "require": { - "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0", - "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0", - "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0", + "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0|^13.0", + "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0|^13.0", "php": "^8.0", - "symfony/console": "^6.0|^7.0", - "symfony/yaml": "^6.0|^7.0" + "symfony/console": "^6.0|^7.0|^8.0", + "symfony/yaml": "^6.0|^7.0|^8.0" }, "require-dev": { - "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0|^11.0", "phpstan/phpstan": "^2.0" }, "bin": [ @@ -7788,7 +7795,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2026-01-01T02:46:03+00:00" + "time": "2026-04-01T15:17:32+00:00" }, { "name": "mockery/mockery", @@ -7935,39 +7942,36 @@ }, { "name": "nunomaduro/collision", - "version": "v8.8.3", + "version": "v8.9.3", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4" + "reference": "b0d8ab95b29c3189aeeb902d81215231df4c1b64" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/1dc9e88d105699d0fee8bb18890f41b274f6b4c4", - "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/b0d8ab95b29c3189aeeb902d81215231df4c1b64", + "reference": "b0d8ab95b29c3189aeeb902d81215231df4c1b64", "shasum": "" }, "require": { - "filp/whoops": "^2.18.1", - "nunomaduro/termwind": "^2.3.1", + "filp/whoops": "^2.18.4", + "nunomaduro/termwind": "^2.4.0", "php": "^8.2.0", - "symfony/console": "^7.3.0" + "symfony/console": "^7.4.8 || ^8.0.4" }, "conflict": { - "laravel/framework": "<11.44.2 || >=13.0.0", - "phpunit/phpunit": "<11.5.15 || >=13.0.0" + "laravel/framework": "<11.48.0 || >=14.0.0", + "phpunit/phpunit": "<11.5.50 || >=14.0.0" }, "require-dev": { - "brianium/paratest": "^7.8.3", - "larastan/larastan": "^3.4.2", - "laravel/framework": "^11.44.2 || ^12.18", - "laravel/pint": "^1.22.1", - "laravel/sail": "^1.43.1", - "laravel/sanctum": "^4.1.1", - "laravel/tinker": "^2.10.1", - "orchestra/testbench-core": "^9.12.0 || ^10.4", - "pestphp/pest": "^3.8.2 || ^4.0.0", - "sebastian/environment": "^7.2.1 || ^8.0" + "brianium/paratest": "^7.8.5", + "larastan/larastan": "^3.9.3", + "laravel/framework": "^11.48.0 || ^12.56.0 || ^13.2.0", + "laravel/pint": "^1.29.0", + "orchestra/testbench-core": "^9.12.0 || ^10.12.1 || ^11.0.0", + "pestphp/pest": "^3.8.5 || ^4.4.3 || ^5.0.0", + "sebastian/environment": "^7.2.1 || ^8.0.4 || ^9.0.0" }, "type": "library", "extra": { @@ -8030,7 +8034,7 @@ "type": "patreon" } ], - "time": "2025-11-20T02:55:25+00:00" + "time": "2026-04-06T19:25:53+00:00" }, { "name": "phar-io/manifest", @@ -8499,16 +8503,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.51", + "version": "11.5.55", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "ad14159f92910b0f0e3928c13e9b2077529de091" + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ad14159f92910b0f0e3928c13e9b2077529de091", - "reference": "ad14159f92910b0f0e3928c13e9b2077529de091", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/adc7262fccc12de2b30f12a8aa0b33775d814f00", + "reference": "adc7262fccc12de2b30f12a8aa0b33775d814f00", "shasum": "" }, "require": { @@ -8581,7 +8585,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.51" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.55" }, "funding": [ { @@ -8605,7 +8609,7 @@ "type": "tidelift" } ], - "time": "2026-02-05T07:59:30+00:00" + "time": "2026-02-18T12:37:06+00:00" }, { "name": "sebastian/cli-parser", @@ -9647,16 +9651,16 @@ }, { "name": "symfony/yaml", - "version": "v7.4.1", + "version": "v7.4.8", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "24dd4de28d2e3988b311751ac49e684d783e2345" + "reference": "c58fdf7b3d6c2995368264c49e4e8b05bcff2883" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/24dd4de28d2e3988b311751ac49e684d783e2345", - "reference": "24dd4de28d2e3988b311751ac49e684d783e2345", + "url": "https://api.github.com/repos/symfony/yaml/zipball/c58fdf7b3d6c2995368264c49e4e8b05bcff2883", + "reference": "c58fdf7b3d6c2995368264c49e4e8b05bcff2883", "shasum": "" }, "require": { @@ -9699,7 +9703,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v7.4.1" + "source": "https://github.com/symfony/yaml/tree/v7.4.8" }, "funding": [ { @@ -9719,7 +9723,7 @@ "type": "tidelift" } ], - "time": "2025-12-04T18:11:45+00:00" + "time": "2026-03-24T13:12:05+00:00" }, { "name": "theseer/tokenizer", @@ -9781,5 +9785,8 @@ "php": "^8.2" }, "platform-dev": {}, + "platform-overrides": { + "php": "8.2.0" + }, "plugin-api-version": "2.6.0" } diff --git a/database/migrations/2026_02_07_130000_create_calon_penerimas_table.php b/database/migrations/2026_02_07_130000_create_calon_penerimas_table.php index 67e8e5d..087ffe5 100644 --- a/database/migrations/2026_02_07_130000_create_calon_penerimas_table.php +++ b/database/migrations/2026_02_07_130000_create_calon_penerimas_table.php @@ -6,37 +6,44 @@ return new class extends Migration { - /** - * Run the migrations. - */ - public function up(): void + public function up(): void { Schema::create('calon_penerimas', function (Blueprint $table) { - $table->id(); // NO. URUT + $table->id(); $table->foreignId('user_id')->constrained('users')->onDelete('cascade'); $table->foreignId('rt_id')->constrained('rts')->onDelete('cascade'); - - // Data Sesuai Kebutuhan - $table->string('no_kk', 16); // NO. KK - $table->string('nik', 16)->unique(); // NO. NIK KTP - $table->string('nama_lengkap'); // NAMA LENGKAP - $table->enum('jenis_kelamin', ['Laki-laki', 'Perempuan']); // JENIS KELAMIN - $table->string('tempat_lahir'); // TEMPAT LAHIR - $table->date('tanggal_lahir'); // TANGGAL LAHIR - $table->text('alamat'); // ALAMAT - $table->string('desa'); // DESA - $table->string('pekerjaan'); // PEKERJAAN - $table->decimal('penghasilan', 15, 2); // PENGHASILAN - $table->integer('jumlah_tanggungan'); // JUMLAH TANGGUNGAN - $table->string('aset_kepemilikan'); // ASET KEPEMILIKAN - $table->enum('bantuan_lain', ['ya', 'tidak']); // BANTUAN LAIN - $table->integer('usia'); // USIA - $table->string('status_perkawinan'); // STATUS PERKAWINAN - - // Untuk sistem (verifikasi admin) + + $table->string('no_kk', 16); + $table->string('nik', 16)->unique(); + $table->string('nama_lengkap'); + $table->enum('jenis_kelamin', ['Laki-laki', 'Perempuan']); + $table->string('tempat_lahir'); + $table->date('tanggal_lahir'); + $table->text('alamat'); + $table->string('desa'); + $table->string('pekerjaan'); + $table->decimal('penghasilan', 15, 2); + $table->integer('jumlah_tanggungan'); + $table->string('aset_kepemilikan'); + $table->string('kondisi_rumah')->default('Tidak Diketahui'); + $table->string('meteran_listrik')->default('Tidak Diketahui'); + $table->string('sumber_air')->default('Tidak Diketahui'); + $table->enum('bantuan_lain', ['ya', 'tidak']); + $table->integer('usia'); + $table->string('status_perkawinan'); $table->enum('status_verifikasi', ['pending', 'disetujui', 'ditolak'])->default('pending'); $table->text('catatan_admin')->nullable(); - + + $table->string('foto_rumah_depan')->nullable(); + $table->string('foto_rumah_belakang')->nullable(); + $table->string('foto_rumah_kanan')->nullable(); + $table->string('foto_rumah_kiri')->nullable(); + $table->string('foto_kk')->nullable(); + $table->string('foto_ktp')->nullable(); + $table->string('foto_rekening_listrik')->nullable(); + $table->string('foto_meteran_air')->nullable(); + $table->string('dokumen_pendukung')->nullable(); + $table->timestamps(); }); } @@ -45,4 +52,4 @@ public function down(): void { Schema::dropIfExists('calon_penerimas'); } -}; +}; \ No newline at end of file diff --git a/database/migrations/2026_02_07_140000_create_prediksi_kelayakans_table.php b/database/migrations/2026_02_07_140000_create_prediksi_kelayakans_table.php index 3d18ad6..bf9f2f8 100644 --- a/database/migrations/2026_02_07_140000_create_prediksi_kelayakans_table.php +++ b/database/migrations/2026_02_07_140000_create_prediksi_kelayakans_table.php @@ -6,16 +6,16 @@ return new class extends Migration { - /** - * Run the migrations. - */ - public function up(): void + public function up(): void { Schema::create('prediksi_kelayakans', function (Blueprint $table) { $table->id(); $table->foreignId('calon_penerima_id')->constrained('calon_penerimas')->onDelete('cascade'); - $table->decimal('probability', 5, 2); // Probabilitas kelayakan (0-100) - $table->string('recommendation'); // Sangat Layak, Layak, Kurang Layak + $table->decimal('probability', 5, 2); + $table->string('recommendation'); + $table->string('kondisi_rumah')->default('Tidak Diketahui'); + $table->string('meteran_listrik')->default('Tidak Diketahui'); + $table->string('sumber_air')->default('Tidak Diketahui'); $table->timestamps(); }); } @@ -24,4 +24,4 @@ public function down(): void { Schema::dropIfExists('prediksi_kelayakans'); } -}; +}; \ No newline at end of file diff --git a/database/migrations/2026_04_17_015802_create_password_reset_tokens_table.php b/database/migrations/2026_04_17_015802_create_password_reset_tokens_table.php new file mode 100644 index 0000000..2ecc465 --- /dev/null +++ b/database/migrations/2026_04_17_015802_create_password_reset_tokens_table.php @@ -0,0 +1,22 @@ +string('email')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + } + + public function down(): void + { + Schema::dropIfExists('password_reset_tokens'); + } +}; \ No newline at end of file diff --git a/error_log b/error_log new file mode 100644 index 0000000..8bc990f --- /dev/null +++ b/error_log @@ -0,0 +1,21 @@ +[08-Apr-2026 16:30:23 UTC] PHP Fatal error: Composer detected issues in your platform: Your Composer dependencies require a PHP version ">= 8.3.0". You are running 8.2.30. in /home/tamyhost/public_html/E31232406/vendor/composer/platform_check.php on line 26 +[08-Apr-2026 17:03:37 UTC] PHP Fatal error: Composer detected issues in your platform: Your Composer dependencies require a PHP version ">= 8.3.0". You are running 8.2.30. in /home/tamyhost/public_html/E31232406/vendor/composer/platform_check.php on line 26 +[08-Apr-2026 17:06:51 UTC] PHP Fatal error: Composer detected issues in your platform: Your Composer dependencies require a PHP version ">= 8.3.0". You are running 8.2.30. in /home/tamyhost/public_html/E31232406/vendor/composer/platform_check.php on line 26 +[08-Apr-2026 17:42:39 UTC] PHP Warning: require(/home/tamyhost/public_html/E31232406/../vendor/autoload.php): Failed to open stream: No such file or directory in /home/tamyhost/public_html/E31232406/index.php on line 14 +[08-Apr-2026 17:42:39 UTC] PHP Warning: require(/home/tamyhost/public_html/E31232406/../vendor/autoload.php): Failed to open stream: No such file or directory in /home/tamyhost/public_html/E31232406/index.php on line 14 +[08-Apr-2026 17:42:39 UTC] PHP Fatal error: Uncaught Error: Failed opening required '/home/tamyhost/public_html/E31232406/../vendor/autoload.php' (include_path='.:/opt/cpanel/ea-php82/root/usr/share/pear') in /home/tamyhost/public_html/E31232406/index.php:14 +Stack trace: +#0 {main} + thrown in /home/tamyhost/public_html/E31232406/index.php on line 14 +[08-Apr-2026 17:42:42 UTC] PHP Warning: require(/home/tamyhost/public_html/E31232406/../vendor/autoload.php): Failed to open stream: No such file or directory in /home/tamyhost/public_html/E31232406/index.php on line 14 +[08-Apr-2026 17:42:42 UTC] PHP Warning: require(/home/tamyhost/public_html/E31232406/../vendor/autoload.php): Failed to open stream: No such file or directory in /home/tamyhost/public_html/E31232406/index.php on line 14 +[08-Apr-2026 17:42:42 UTC] PHP Fatal error: Uncaught Error: Failed opening required '/home/tamyhost/public_html/E31232406/../vendor/autoload.php' (include_path='.:/opt/cpanel/ea-php82/root/usr/share/pear') in /home/tamyhost/public_html/E31232406/index.php:14 +Stack trace: +#0 {main} + thrown in /home/tamyhost/public_html/E31232406/index.php on line 14 +[08-Apr-2026 17:42:43 UTC] PHP Warning: require(/home/tamyhost/public_html/E31232406/../vendor/autoload.php): Failed to open stream: No such file or directory in /home/tamyhost/public_html/E31232406/index.php on line 14 +[08-Apr-2026 17:42:43 UTC] PHP Warning: require(/home/tamyhost/public_html/E31232406/../vendor/autoload.php): Failed to open stream: No such file or directory in /home/tamyhost/public_html/E31232406/index.php on line 14 +[08-Apr-2026 17:42:43 UTC] PHP Fatal error: Uncaught Error: Failed opening required '/home/tamyhost/public_html/E31232406/../vendor/autoload.php' (include_path='.:/opt/cpanel/ea-php82/root/usr/share/pear') in /home/tamyhost/public_html/E31232406/index.php:14 +Stack trace: +#0 {main} + thrown in /home/tamyhost/public_html/E31232406/index.php on line 14 diff --git a/ml/predict.py b/ml/predict.py index 7b9a399..651a581 100644 --- a/ml/predict.py +++ b/ml/predict.py @@ -2,15 +2,19 @@ import json import sys def predict(data): - pekerjaan = str(data.get("pekerjaan","")).lower() - penghasilan = float(data.get("penghasilan",0)) - tanggungan = int(data.get("jumlah_tanggungan",0)) - aset = str(data.get("aset_kepemilikan","")).lower() - bantuan_lain = str(data.get("bantuan_lain","")).lower() - usia = int(data.get("usia",0)) + pekerjaan = str(data.get("pekerjaan", "")).lower() + penghasilan = float(data.get("penghasilan", 0)) + tanggungan = int(data.get("jumlah_tanggungan", 0)) + aset = str(data.get("aset_kepemilikan", "")).lower() + bantuan_lain = str(data.get("bantuan_lain", "")).lower() + usia = int(data.get("usia", 0)) + kondisi_rumah = str(data.get("kondisi_rumah", "")).lower() + meteran_listrik= str(data.get("meteran_listrik", "")).lower() + sumber_air = str(data.get("sumber_air", "")).lower() score = 0 + # Parameter lama (tidak diubah) if pekerjaan in ["buruh", "tidak bekerja", "petani", "nelayan"]: score += 0.2 @@ -31,22 +35,32 @@ def predict(data): if usia >= 60: score += 0.1 - probability = max(0, min(score,1)) + # Parameter baru + if kondisi_rumah == "tidak layak": + score += 0.15 + elif kondisi_rumah == "sedang": + score += 0.05 + + if meteran_listrik == "450va": + score += 0.1 + elif meteran_listrik == "900va": + score += 0.05 + + if sumber_air == "sungai": + score += 0.1 + elif sumber_air == "sumur": + score += 0.05 + + probability = max(0, min(score, 1)) recommendation = "Layak" if probability >= 0.5 else "Tidak Layak" return { - "probability": round(probability,4), + "probability": round(probability, 4), "recommendation": recommendation } def read_input(): - """ - Prioritas baca: - 1) STDIN (kalau ada) - 2) argv[1] (kalau ada) - """ try: - # Coba baca dari STDIN if not sys.stdin.isatty(): raw = sys.stdin.read().strip() if raw: @@ -54,7 +68,6 @@ def read_input(): except: pass - # Fallback ke argv if len(sys.argv) > 1: raw = sys.argv[1] return json.loads(raw) @@ -63,7 +76,7 @@ def read_input(): if __name__ == "__main__": try: - data = read_input() + data = read_input() result = predict(data) print(json.dumps(result)) except Exception as e: diff --git a/public/login-gedung.jpg b/public/login-gedung.jpg new file mode 100644 index 0000000..8d2491e Binary files /dev/null and b/public/login-gedung.jpg differ diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php index 85af2ad..48d1615 100644 --- a/resources/views/admin/dashboard.blade.php +++ b/resources/views/admin/dashboard.blade.php @@ -1,16 +1,15 @@ -
+
-

Dashboard Kelurahan

-

Ringkasan data kelayakan penerima BLT-DD seluruh dusun

+

Dashboard Kelurahan

+

Ringkasan data kelayakan penerima BLT-DD

-
- - {{-- โ”€โ”€ BELL NOTIFIKASI โ”€โ”€ --}} +
+ {{-- BELL --}}
- - {{-- Clock --}} -
+ {{-- CLOCK --}} +
@@ -43,121 +41,112 @@ -
+
- {{-- GREETING + NOTIFIKASI (asli tidak diubah, hanya ganti class ke inline style) --}} -
-
+ {{-- GREETING --}} +
+
{{ strtoupper(substr(Auth::user()->name ?? 'A', 0, 1)) }}
@@ -166,11 +155,9 @@ function clearNotifs() { NS.clearAll(); renderNotifs(); }

Panel admin โ€” kelola dan pantau seluruh data warga.

-
-
- - - +
+
+

{{ $totalPending ?? 0 }} data menunggu verifikasi

@@ -179,303 +166,200 @@ function clearNotifs() { NS.clearAll(); renderNotifs(); }
- {{-- STAT CARDS (asli tidak diubah, ganti ke inline style) --}} -
+ {{-- STAT CARDS --}} +
-
+ @php + $cards = [ + ['label'=>'Total Warga','sub'=>'Dari semua dusun','val'=>$totalWarga??0,'grad'=>'#2563eb,#1d4ed8','shadow'=>'rgba(37,99,235,.3)','icon'=>'M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z','tc'=>'rgba(191,219,254,.9)'], + ['label'=>'Pending','sub'=>'Belum diproses','val'=>$totalPending??0,'grad'=>'#f59e0b,#d97706','shadow'=>'rgba(245,158,11,.3)','icon'=>'M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z','tc'=>'rgba(254,243,199,.9)'], + ['label'=>'Diterima','sub'=>'Sudah ditetapkan','val'=>$totalPenerima??0,'grad'=>'#10b981,#059669','shadow'=>'rgba(16,185,129,.3)','icon'=>'M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z','tc'=>'rgba(167,243,208,.9)'], + ['label'=>'Ditolak','sub'=>'Tidak memenuhi syarat','val'=>$totalDitolak??0,'grad'=>'#f43f5e,#e11d48','shadow'=>'rgba(244,63,94,.3)','icon'=>'M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z','tc'=>'rgba(254,205,211,.9)'], + ]; + @endphp + + @foreach($cards as $c) +
-

Total Warga Masuk

-

{{ $totalWarga ?? 0 }}

-

Dari semua dusun

+

{{ $c['label'] }}

+

{{ $c['val'] }}

+

{{ $c['sub'] }}

-
- -
-
- -
-
-
-

Pending Verifikasi

-

{{ $totalPending ?? 0 }}

-

Belum diproses

-
-
- -
-
- -
-
-
-

Diterima / Ditetapkan

-

{{ $totalPenerima ?? 0 }}

-

Sudah ditetapkan

-
-
- -
-
- -
-
-
-

Ditolak

-

{{ $totalDitolak ?? 0 }}

-

Tidak memenuhi syarat

-
-
- +
+
+ @endforeach
- {{-- GRAFIK + DATA PER DUSUN (logika PHP asli 100% tidak diubah) --}} -
+ {{-- GRAFIK + DATA PER DUSUN --}} +
+ {{-- Grafik --}}
-
+
-
-

Jumlah Warga per Dusun

+
+

Warga per Dusun

- {{ $wargaPerDusun->sum('total') }} total warga + {{ $wargaPerDusun->sum('total') }} total
-
+
@php - $dusuns = $wargaPerDusun->values(); - $n = max($dusuns->count(), 1); - $maxV = max((int)$dusuns->max('total'), 1); - - $W = 560; $H = 210; - $pL = 40; $pR = 20; - $pT = 30; $pB = 45; - $cW = $W - $pL - $pR; - $cH = $H - $pT - $pB; - - $step = max(1, (int)ceil($maxV / 4)); - $yTicks = range(0, $maxV + $step, $step); - - $pts = []; - foreach ($dusuns as $i => $d) { - $x = $pL + ($n === 1 ? $cW / 2 : ($i / ($n - 1)) * $cW); - $y = $pT + $cH - ($d->total / $maxV) * $cH; - $pts[] = ['x' => round($x, 1), 'y' => round($y, 1), 'val' => $d->total, 'name' => $d->dusun]; + $dusuns=$wargaPerDusun->values(); + $n=max($dusuns->count(),1); + $maxV=max((int)$dusuns->max('total'),1); + $W=560;$H=200;$pL=40;$pR=20;$pT=28;$pB=44; + $cW=$W-$pL-$pR;$cH=$H-$pT-$pB; + $step=max(1,(int)ceil($maxV/4)); + $yTicks=range(0,$maxV+$step,$step); + $pts=[]; + foreach($dusuns as $i=>$d){ + $x=$pL+($n===1?$cW/2:($i/($n-1))*$cW); + $y=$pT+$cH-($d->total/$maxV)*$cH; + $pts[]=['x'=>round($x,1),'y'=>round($y,1),'val'=>$d->total,'name'=>$d->dusun]; } - - $poly = implode(' ', array_map(fn($p) => "{$p['x']},{$p['y']}", $pts)); - $firstPt = $pts[0]; - $lastPt = $pts[count($pts)-1]; - $botY = $pT + $cH; - $areaPath = "M {$firstPt['x']},{$firstPt['y']} " - . implode(' ', array_map(fn($p) => "L {$p['x']},{$p['y']}", array_slice($pts, 1))) - . " L {$lastPt['x']},{$botY} L {$firstPt['x']},{$botY} Z"; + $poly=implode(' ',array_map(fn($p)=>"{$p['x']},{$p['y']}",$pts)); + $firstPt=$pts[0];$lastPt=$pts[count($pts)-1]; + $botY=$pT+$cH; + $areaPath="M {$firstPt['x']},{$firstPt['y']} ".implode(' ',array_map(fn($p)=>"L {$p['x']},{$p['y']}",array_slice($pts,1)))." L {$lastPt['x']},{$botY} L {$firstPt['x']},{$botY} Z"; @endphp - - + - - + + - @foreach($yTicks as $t) - @if($t <= $maxV + $step) - @php $gy = $pT + $cH - min($t, $maxV) / $maxV * $cH; @endphp - - {{ $t }} + @if($t<=$maxV+$step) + @php $gy=$pT+$cH-min($t,$maxV)/$maxV*$cH; @endphp + + {{ $t }} @endif @endforeach - - Jumlah Warga - - + - - + @foreach($pts as $p) - {{ $p['val'] }} - {{ Str::limit($p['name'], 9) }} + {{ $p['val'] }} + {{ Str::limit($p['name'],8) }} @endforeach - Dusun
+ {{-- Data per dusun --}}
-
-
-

Data Per Dusun

+
+
+

Per Dusun

-
- @php $maxDusun = $wargaPerDusun->max('total') ?: 1; @endphp +
+ @php $maxDusun=$wargaPerDusun->max('total')?:1; @endphp @foreach($wargaPerDusun as $data) -
-
-
-
- - - -
- {{ $data->dusun }} -
- {{ $data->total }} -
-
-
-
+
+
+ {{ $data->dusun }} + {{ $data->total }}
+
+
+
+
@endforeach
- {{-- TOP 10 โ€” full width, tambah kolom Dusun & RT, logika asli 100% tidak diubah --}} + {{-- TOP 10 --}}
-
+
-
+

Top 10 Probabilitas Tertinggi

-

Seluruh dusun โ€” diurutkan dari probabilitas terbesar

+

Diurutkan dari probabilitas terbesar

-
-
- โ‰ฅ70% - 40โ€“70% - <40% -
- - Lihat Semua - - -
+ + Lihat Semua + +
-
+
- + - - + - + @forelse($topWarga as $index => $warga) - - {{-- Rank (asli) --}} - - - {{-- Nama (asli) --}} - + + - - {{-- NIK (asli) --}} - - - {{-- Dusun (ditambahkan โ€” pakai $warga->dusun yang sudah ada di data asli) --}} - - - {{-- RT (ditambahkan โ€” pakai $warga->rt jika ada) --}} - - - {{-- Penghasilan (asli) --}} - - - {{-- Probabilitas (asli) --}} - - - {{-- Status (asli) --}} - - + + + + + + + + @empty - - - + @endforelse
Rank# Nama NIKDusunRTDusun / RT PenghasilanProbabilitasProbabilitas Status
- @if($index == 0) -
1
- @elseif($index == 1) -
2
- @elseif($index == 2) -
3
- @else -
{{ $index + 1 }}
- @endif -
-
-
- {{ strtoupper(substr($warga->nama, 0, 1)) }} -
-
-
{{ $warga->nama }}
-
{{ $warga->pekerjaan }}
-
+
+ @php + $rk = ['linear-gradient(135deg,#f59e0b,#d97706)','linear-gradient(135deg,#94a3b8,#64748b)','linear-gradient(135deg,#f97316,#ea580c)']; + $bg = $index < 3 ? $rk[$index] : '#f1f5f9'; + $tc = $index < 3 ? '#fff' : '#64748b'; + @endphp +
{{ $index+1 }}
+
+
+
+ {{ strtoupper(substr($warga->nama,0,1)) }}
-
- {{ $warga->nik }} - - - {{ $warga->dusun }} - - - RT {{ str_pad($warga->rt ?? '0', 3, '0', STR_PAD_LEFT) }} - - Rp {{ number_format($warga->penghasilan, 0, ',', '.') }} - - @php - $sc = $warga->probabilitas >= 70 ? '#10b981' : ($warga->probabilitas >= 40 ? '#f59e0b' : '#f43f5e'); - $scB = $warga->probabilitas >= 70 ? '#f0fdf4' : ($warga->probabilitas >= 40 ? '#fffbeb' : '#fff1f2'); - @endphp -
-
-
-
- - {{ number_format($warga->probabilitas, 1) }}% - +
+
{{ $warga->nama }}
+
{{ $warga->pekerjaan }}
-
- @if($warga->status == 'pending') - - Pending - - @elseif($warga->status == 'diterima') - - Diterima - - @elseif($warga->status == 'ditolak') - - Ditolak - - @else - - {{ ucfirst($warga->status) }} - - @endif -
{{ $warga->nik }} +
+ {{ $warga->dusun }} + RT {{ str_pad($warga->rt??'0',3,'0',STR_PAD_LEFT) }} +
+
Rp {{ number_format($warga->penghasilan,0,',','.') }} + @php $sc=$warga->probabilitas>=70?'#10b981':($warga->probabilitas>=40?'#f59e0b':'#f43f5e'); @endphp +
+
+
+
+ {{ number_format($warga->probabilitas,1) }}% +
+
+ @php + $st=['pending'=>['#fffbeb','#b45309','#fde68a','Pending'],'diterima'=>['#f0fdf4','#166534','#bbf7d0','Diterima'],'ditolak'=>['#fff1f2','#be123c','#fecdd3','Ditolak']]; + $s=$st[$warga->status]??['#eff6ff','#1d4ed8','#bfdbfe',ucfirst($warga->status)]; + @endphp + + {{ $s[3] }} + +
-
-
- -
-

Belum ada data warga

-
-
Belum ada data warga
diff --git a/resources/views/admin/data-akun.blade.php b/resources/views/admin/data-akun.blade.php index fe6d631..ad4802c 100644 --- a/resources/views/admin/data-akun.blade.php +++ b/resources/views/admin/data-akun.blade.php @@ -1,299 +1,383 @@ -
+
-

Data Akun

-

Kelola akun Admin & RT yang menggunakan sistem.

+

Data Akun

+

Kelola akun Admin & RT yang menggunakan sistem

-
- - - - @if(isset($users) && method_exists($users, 'total')) - {{ $users->total() }} akun terdaftar - @endif + @if(isset($users) && method_exists($users,'total')) +
+ + {{ $users->total() }} akun terdaftar
+ @endif
-
+ + + {{-- FLASH --}} + @if(session('success')) +
+ + {{ session('success') }}
+ @endif + @if(session('error')) +
+ + {{ session('error') }} +
+ @endif - {{-- TABLE CARD --}} -
- -
-
-
- - Daftar Akun - @if(isset($users) && method_exists($users, 'total')) - ({{ $users->total() }} akun) - @endif - -
- @if(isset($users) && method_exists($users, 'currentPage') && $users->lastPage() > 1) - Hal. {{ $users->currentPage() }} / {{ $users->lastPage() }} - @endif + {{-- SEARCH --}} +
+
+
+

Pencarian

+
+
+
+ +
- -
- - - - - - - - - - - - - - - - - - - - - @forelse($users ?? [] as $u) - @php - $isMe = ($u->id === auth()->id()); - $isActive = isset($u->is_active) ? (bool)$u->is_active : true; - $isAdmin = $u->role === 'admin'; - $newRole = $isAdmin ? 'rt' : 'admin'; - $newRoleLabel = $isAdmin ? 'RT' : 'Admin'; - $initial = strtoupper(substr($u->name, 0, 1)); - $avatarGrad = $isAdmin - ? 'from-emerald-500 to-emerald-600 shadow-emerald-200' - : 'from-blue-500 to-blue-600 shadow-blue-200'; - @endphp - - - - {{-- NAMA --}} - - - {{-- EMAIL --}} - - - {{-- ROLE --}} - - - {{-- STATUS --}} - - - {{-- AKSI --}} - - - - @empty - - - - @endforelse - -
NamaEmailRoleStatusAksi
-
-
-
- {{ $initial }} -
- @if($isActive) - - @endif -
-
-
- {{ $u->name }} - @if($isMe) - Kamu - @endif -
-
ID #{{ $u->id }}
-
-
-
- {{ $u->email }} - - @if($isAdmin) - - - - - Admin - - @else - - - - - RT - - @endif - - @if($isActive) - - - Aktif - - @else - - - Nonaktif - - @endif - -
- @if($isMe) - - - - - Terkunci - - @else - {{-- UBAH ROLE --}} - - @csrf - - - - - {{-- AKTIF / NONAKTIF --}} -
- @csrf - -
- - {{-- HAPUS --}} -
- @csrf - @method('DELETE') - -
- @endif -
-
-
-
- - - -
-
-

Belum ada akun

- @if(request()->filled('q')) -

Tidak ada hasil untuk "{{ request('q') }}"

- โ† Hapus pencarian - @endif -
-
-
-
- - {{-- PAGINATION --}} - @if(isset($users) && method_exists($users, 'links') && $users->hasPages()) -
- {{ $users->appends(request()->query())->links() }} -
+ + @if(request()->filled('q')) + + + @endif - - {{-- CREDIT WATERMARK --}} -
- - - - Aplikasi SiBantuDes - ยท - Desa Ngerong -
-
- +
+ {{-- TABLE CARD --}} +
+
+
+
+ + Daftar Akun + @if(isset($users) && method_exists($users,'total')) + ({{ $users->total() }} akun) + @endif + +
+ @if(isset($users) && method_exists($users,'currentPage') && $users->lastPage() > 1) + Hal. {{ $users->currentPage() }} / {{ $users->lastPage() }} + @endif +
+ + {{-- โ”€โ”€ DESKTOP TABLE โ”€โ”€ --}} +
+ + + + + + + + + + + + @forelse($users ?? [] as $u) + @php + $isMe = ($u->id === auth()->id()); + $isActive = isset($u->is_active) ? (bool)$u->is_active : true; + $isAdmin = $u->role === 'admin'; + $newRole = $isAdmin ? 'rt' : 'admin'; + $newRoleLabel = $isAdmin ? 'RT' : 'Admin'; + $initial = strtoupper(substr($u->name,0,1)); + $avBg = $isAdmin + ? 'background:linear-gradient(135deg,#10b981,#059669);' + : 'background:linear-gradient(135deg,#3b82f6,#2563eb);'; + @endphp + + + {{-- NAMA --}} + + + {{-- EMAIL --}} + + + {{-- ROLE --}} + + + {{-- STATUS --}} + + + {{-- AKSI --}} + + + @empty + + @endforelse + +
NamaEmailRoleStatusAksi
+
+
+
{{ $initial }}
+ @if($isActive)
@endif +
+
+
+ {{ $u->name }} + @if($isMe) + Kamu + @endif +
+
ID #{{ $u->id }}
+
+
+
+ {{ $u->email }} + + @if($isAdmin) + + Admin + + @else + + RT + + @endif + + @if($isActive) + + Aktif + + @else + + Nonaktif + + @endif + +
+ @if($isMe) + + + Terkunci + + @else + {{-- Ubah role --}} +
+ @csrf + + +
+ + {{-- Toggle aktif --}} +
+ @csrf + +
+ + {{-- Hapus --}} +
+ @csrf @method('DELETE') + +
+ @endif +
+
+
+
+ +
+

Belum ada akun

+ @if(request()->filled('q')) +

Tidak ada hasil untuk "{{ request('q') }}"

+ โ† Hapus pencarian + @endif +
+
+
+ + {{-- โ”€โ”€ MOBILE CARD VIEW โ”€โ”€ --}} +
+ @forelse($users ?? [] as $u) + @php + $isMe = ($u->id === auth()->id()); + $isActive = isset($u->is_active) ? (bool)$u->is_active : true; + $isAdmin = $u->role === 'admin'; + $newRole = $isAdmin ? 'rt' : 'admin'; + $newRoleLabel = $isAdmin ? 'RT' : 'Admin'; + $initial = strtoupper(substr($u->name,0,1)); + $avBg = $isAdmin + ? 'background:linear-gradient(135deg,#10b981,#059669);' + : 'background:linear-gradient(135deg,#3b82f6,#2563eb);'; + @endphp +
+
+
+
{{ $initial }}
+ @if($isActive)
@endif +
+
+
+ {{ $u->name }} + @if($isMe) + Kamu + @endif +
+
{{ $u->email }}
+
+
+ +
+ @if($isAdmin) + Admin + @else + RT + @endif + + @if($isActive) + Aktif + @else + Nonaktif + @endif + + ID #{{ $u->id }} +
+ +
+ @if($isMe) + + + Terkunci + + @else +
+ @csrf + + +
+ +
+ @csrf + +
+ +
+ @csrf @method('DELETE') + +
+ @endif +
+
+ @empty +
+

Belum ada akun

+
+ @endforelse +
+ + {{-- PAGINATION --}} + @if(isset($users) && method_exists($users,'links') && $users->hasPages()) +
+ {{ $users->appends(request()->query())->links() }} +
+ @endif + + {{-- WATERMARK --}} +
+ + SiBantuDes ยท Desa Ngerong +
+
+ + + \ No newline at end of file diff --git a/resources/views/admin/data-warga.blade.php b/resources/views/admin/data-warga.blade.php index 0536a25..4cfd2b9 100644 --- a/resources/views/admin/data-warga.blade.php +++ b/resources/views/admin/data-warga.blade.php @@ -1,138 +1,137 @@ -
+
-

Data Warga

-

Kelola dan pantau seluruh data warga dari semua dusun

+

Data Warga

+

Kelola dan pantau seluruh data warga dari semua dusun

-
+
- {{ \Carbon\Carbon::now('Asia/Jakarta')->translatedFormat('l, d F Y') }} โ€” {{ \Carbon\Carbon::now('Asia/Jakarta')->format('H:i') }} WIB + {{ \Carbon\Carbon::now('Asia/Jakarta')->translatedFormat('d F Y') }} โ€” {{ \Carbon\Carbon::now('Asia/Jakarta')->format('H:i') }} WIB
- {{-- FLASH --}} @if(session('success')) -
+
{{ session('success') }}
@endif @if(session('error')) -
+
{{ session('error') }}
@endif - {{-- SEARCH --}} -
+
-

Pencarian

+

Pencarian & Filter

-
-
+ +
- - - @if(request()->filled('q')) - + @endif
-
- @csrf - @method('DELETE') + @csrf @method('DELETE')
- {{-- TABLE --}}
-
+
-
+
Daftar Warga @if(isset($wargas) && method_exists($wargas,'total')) @@ -160,17 +158,13 @@ @endif
-
+
- - - - - - + + @@ -188,57 +182,56 @@ if(strtolower($warga->pekerjaan??'')==='tidak bekerja') $positive[]='Tidak bekerja'; elseif(in_array(strtolower($warga->pekerjaan??''),['buruh harian','buruh','petani','nelayan'])) $positive[]='Pekerjaan tergolong rentan'; else $negative[]='Memiliki pekerjaan relatif stabil'; - if(($warga->penghasilan??0)<=1000000) $positive[]='Penghasilan rendah'; elseif(($warga->penghasilan??0)<=2000000) $positive[]='Penghasilan tergolong rendah'; else $negative[]='Penghasilan relatif tinggi'; - if(($warga->jumlah_tanggungan??0)>=4) $positive[]='Tanggungan banyak'; elseif(($warga->jumlah_tanggungan??0)>=2) $positive[]='Tanggungan cukup banyak'; else $negative[]='Tanggungan sedikit'; - $aset=strtolower($warga->aset_kepemilikan??''); if(str_contains($aset,'mobil')) $negative[]='Memiliki aset mobil'; if(str_contains($aset,'motor')) $negative[]='Memiliki kendaraan bermotor'; if(str_contains($aset,'rumah')) $negative[]='Memiliki aset rumah'; if(in_array($aset,['tidak ada','-','tidak punya'])) $positive[]='Tidak memiliki aset berarti'; - if(strtolower($warga->bantuan_lain??'')==='ya') $negative[]='Sudah menerima bantuan lain'; else $positive[]='Belum menerima bantuan lain'; - if(($warga->usia??0)>=60) $positive[]='Usia lanjut'; elseif(($warga->usia??0)>=45) $positive[]='Usia cukup rentan'; - $summary='Nilai kelayakan dihitung berdasarkan pekerjaan, penghasilan, tanggungan, aset, bantuan lain, dan usia.'; + // Parameter baru + if(strtolower($warga->kondisi_rumah??'')==='tidak layak') $positive[]='Kondisi rumah tidak layak huni'; + elseif(strtolower($warga->kondisi_rumah??'')==='sedang') $positive[]='Kondisi rumah sedang'; + else $negative[]='Kondisi rumah layak'; + if(($warga->meteran_listrik??'')==='450VA') $positive[]='Meteran listrik 450VA'; + elseif(($warga->meteran_listrik??'')==='900VA') $positive[]='Meteran listrik 900VA'; + else $negative[]='Meteran listrik 1300VA ke atas'; + if(strtolower($warga->sumber_air??'')==='sungai') $positive[]='Sumber air sungai'; + elseif(strtolower($warga->sumber_air??'')==='sumur') $positive[]='Sumber air sumur'; + else $negative[]='Sumber air PDAM'; + + $summary='Nilai kelayakan dihitung berdasarkan pekerjaan, penghasilan, tanggungan, aset, bantuan lain, usia, kondisi rumah, meteran listrik, dan sumber air.'; if(count($positive)&&count($negative)) $summary.=' Terdapat faktor pendukung dan pengurang.'; elseif(count($positive)) $summary.=' Faktor mayoritas mendukung kelayakan.'; else $summary.=' Faktor mayoritas menurunkan kelayakan.'; $dp=[ - 'nik'=>$warga->nik, - 'no_kk'=>$warga->no_kk??'-', - 'nama_lengkap'=>$warga->nama_lengkap, - 'jenis_kelamin'=>$warga->jenis_kelamin??'-', + 'nik'=>$warga->nik,'no_kk'=>$warga->no_kk??'-', + 'nama_lengkap'=>$warga->nama_lengkap,'jenis_kelamin'=>$warga->jenis_kelamin??'-', 'tempat_lahir'=>$warga->tempat_lahir??'-', 'tanggal_lahir'=>$warga->tanggal_lahir?\Carbon\Carbon::parse($warga->tanggal_lahir)->translatedFormat('d F Y'):'-', - 'usia'=>$warga->usia??'-', - 'status_perkawinan'=>$warga->status_perkawinan??'-', - 'alamat'=>$warga->alamat??'-', - 'desa'=>$warga->desa??'-', + 'usia'=>$warga->usia??'-','status_perkawinan'=>$warga->status_perkawinan??'-', + 'alamat'=>$warga->alamat??'-','desa'=>$warga->desa??'-', 'aset_kepemilikan'=>$warga->aset_kepemilikan??'-', - 'pekerjaan'=>$warga->pekerjaan??'-', - 'penghasilan'=>$warga->penghasilan??0, - 'jumlah_tanggungan'=>$warga->jumlah_tanggungan??'-', - 'bantuan_lain'=>$warga->bantuan_lain??'-', - 'status_verifikasi'=>$warga->status_verifikasi??'-', - 'tracking_status'=>$warga->tracking_status??'-', - 'dusun'=>$warga->rt->dusun->nama_dusun??'-', - 'rt'=>$warga->rt->nomor_rt??'-', + 'kondisi_rumah'=>$warga->kondisi_rumah??'-', + 'meteran_listrik'=>$warga->meteran_listrik??'-', + 'sumber_air'=>$warga->sumber_air??'-', + 'pekerjaan'=>$warga->pekerjaan??'-','penghasilan'=>$warga->penghasilan??0, + 'jumlah_tanggungan'=>$warga->jumlah_tanggungan??'-','bantuan_lain'=>$warga->bantuan_lain??'-', + 'status_verifikasi'=>$warga->status_verifikasi??'-','tracking_status'=>$warga->tracking_status??'-', + 'dusun'=>$warga->rt->dusun->nama_dusun??'-','rt'=>$warga->rt->nomor_rt??'-', 'probability'=>optional($warga->prediksiKelayakan)->probability, 'recommendation'=>optional($warga->prediksiKelayakan)->recommendation, - 'positive'=>$positive, - 'negative'=>$negative, - 'summary'=>$summary, + 'positive'=>$positive,'negative'=>$negative,'summary'=>$summary, 'input_oleh'=>optional($warga->user)->name??(optional($warga->user)->email??'-'), 'created_at'=>optional($warga->created_at)->translatedFormat('d F Y, H:i')??'-' ]; @@ -246,37 +239,34 @@ @endphp - - - - - - - @@ -351,7 +335,9 @@ @if(isset($wargas) && method_exists($wargas,'links') && $wargas->hasPages()) -
{{ $wargas->links() }}
+
+ {{ $wargas->links() }} +
@endif @@ -359,19 +345,30 @@
NIKNamaDusun / RTNama / PekerjaanDusun ยท RT Penghasilan Probabilitas Tracking
{{ $warga->nik }} -
+
{{ strtoupper(substr($warga->nama_lengkap,0,1)) }}
-
{{ $warga->nama_lengkap }}
+
{{ $warga->nama_lengkap }}
{{ $warga->pekerjaan??'-' }}
-
{{ $warga->rt->dusun->nama_dusun??'-' }}
+
{{ $warga->rt->dusun->nama_dusun??'-' }}
RT {{ str_pad($warga->rt->nomor_rt??'-',3,'0',STR_PAD_LEFT) }}
+ Rp {{ number_format($warga->penghasilan??0,0,',','.') }} @if($probPct !== null)
-
+
+
+
{{ number_format($probPct,1) }}%
@else โ€” @endif
@if($trk==='terkirim') Terkirim @@ -288,14 +278,12 @@ โ€” @endif
- @if($trk==='terkirim') @csrf @@ -305,20 +293,17 @@ @endif - @if($trk==='sedang_validasi') - Lanjutkan lewat filterisasi + Lanjut filterisasi @endif - @if($trk==='selesai') - @if(($warga->status_verifikasi ?? '') === 'disetujui') + @if(($warga->status_verifikasi??'') === 'disetujui') Diterima - @elseif(($warga->status_verifikasi ?? '') === 'ditolak') - Tidak Diterima + @elseif(($warga->status_verifikasi??'') === 'ditolak') + Ditolak @else Pending @endif -
@csrf
-
+ + + + + + + + + + + + + @forelse(($candidates??[]) as $index => $w) + @php + $prob = $w->prob ?? optional($w->prediksiKelayakan)->probability; + $probPct = $prob !== null ? ($prob<=1 ? $prob*100 : $prob) : null; + $sc = $probPct !== null ? ($probPct>=70?'#10b981':($probPct>=40?'#f59e0b':'#f43f5e')) : '#e5e7eb'; + $picked = isset($pickedIds) ? $pickedIds->contains($w->id) : false; + $rank = (($candidates->currentPage()-1)*$candidates->perPage())+$index+1; + @endphp + -
-
RankNamaNIKDusunProbabilitasStatusFinal
- - - - - - - - - + {{-- Rank --}} + + + {{-- Nama --}} + + + {{-- NIK --}} + + + {{-- Dusun --}} + + + {{-- Probabilitas --}} + + + {{-- Status verifikasi --}} + + + {{-- Final (terpilih) --}} + - + @empty + + @endforelse + +
RankingNamaNIKDusunProbabilitasStatusFinal + @php + $rk = ['linear-gradient(135deg,#f59e0b,#d97706)','linear-gradient(135deg,#94a3b8,#64748b)','linear-gradient(135deg,#f97316,#ea580c)']; + $rbg = $rank<=3 ? $rk[$rank-1] : '#f1f5f9'; + $rtc = $rank<=3 ? '#fff' : '#64748b'; + @endphp +
{{ $rank }}
+
+
+
+ {{ strtoupper(substr($w->nama_lengkap,0,1)) }} +
+ {{ $w->nama_lengkap }} +
+
+ {{ $w->nik }} + + {{ optional(optional($w->rt)->dusun)->nama_dusun ?? '-' }} + + @if($probPct !== null) +
+
+
+
+ {{ number_format((float)$probPct,1) }}% +
+ @else + โ€” + @endif +
+ @php + $sv=['pending'=>['#fffbeb','#b45309','#fde68a','Pending'],'disetujui'=>['#f0fdf4','#166534','#bbf7d0','Disetujui'],'ditolak'=>['#fff1f2','#9f1239','#fecdd3','Ditolak']]; + $sv=$sv[$w->status_verifikasi??'']??['#f3f4f6','#6b7280','#e5e7eb',ucfirst($w->status_verifikasi??'-')]; + @endphp + + {{ $sv[3] }} + + + @if($picked) + + Terpilih + + @else + + Belum + + @endif +
+
+
+ +
+

Pilih dusun untuk menampilkan kandidat

+
+
+
- - @forelse(($candidates ?? []) as $index => $w) - @php - $prob = $w->prob ?? optional($w->prediksiKelayakan)->probability; - $probPct = $prob !== null ? ($prob <= 1 ? $prob * 100 : $prob) : null; - $picked = isset($pickedIds) ? $pickedIds->contains($w->id) : false; - @endphp - - - {{ (($candidates->currentPage() - 1) * $candidates->perPage()) + $index + 1 }} - + {{-- MOBILE CARD VIEW --}} +
+ @forelse(($candidates??[]) as $index => $w) + @php + $prob = $w->prob ?? optional($w->prediksiKelayakan)->probability; + $probPct = $prob !== null ? ($prob<=1 ? $prob*100 : $prob) : null; + $sc = $probPct!==null ? ($probPct>=70?'#10b981':($probPct>=40?'#f59e0b':'#f43f5e')) : '#e5e7eb'; + $picked = isset($pickedIds) ? $pickedIds->contains($w->id) : false; + $rank = (($candidates->currentPage()-1)*$candidates->perPage())+$index+1; + $sv=['pending'=>['#fffbeb','#b45309','Pending'],'disetujui'=>['#f0fdf4','#166534','Disetujui'],'ditolak'=>['#fff1f2','#9f1239','Ditolak']]; + $sv=$sv[$w->status_verifikasi??'']??['#f3f4f6','#6b7280',ucfirst($w->status_verifikasi??'-')]; + @endphp +
+
+ {{-- rank --}} + @php + $rk = ['linear-gradient(135deg,#f59e0b,#d97706)','linear-gradient(135deg,#94a3b8,#64748b)','linear-gradient(135deg,#f97316,#ea580c)']; + $rbg = $rank<=3 ? $rk[$rank-1] : '#f1f5f9'; + $rtc = $rank<=3 ? '#fff' : '#64748b'; + @endphp +
{{ $rank }}
- {{ $w->nama_lengkap }} + {{-- avatar + nama --}} +
+
{{ $w->nama_lengkap }}
+
{{ $w->nik }}
+
- {{ $w->nik }} + {{-- final status --}} + @if($picked) + โœ“ Terpilih + @endif +
- {{ optional(optional($w->rt)->dusun)->nama_dusun ?? '-' }} +
+ {{-- dusun --}} + + {{ optional(optional($w->rt)->dusun)->nama_dusun ?? '-' }} + - - @if($probPct !== null) - {{ number_format((float)$probPct, 1) }}% - @else - - - @endif - + {{-- status --}} + + {{ $sv[2] }} + - - @if(($w->status_verifikasi ?? '') === 'pending') - Pending - @elseif(($w->status_verifikasi ?? '') === 'disetujui') - Disetujui - @else - Ditolak - @endif - - - - @if($picked) - Terpilih - @else - Belum - @endif - - - @empty - - - Pilih dusun dulu untuk menampilkan kandidat filterisasi. - - - @endforelse - - -
- - @if(isset($candidates) && method_exists($candidates, 'links') && $candidates->hasPages()) -
- {{ $candidates->appends(request()->query())->links() }} + {{-- probabilitas --}} + @if($probPct !== null) +
+
+
+
+ {{ number_format((float)$probPct,1) }}% +
+ @endif +
- @endif + @empty +
+

Pilih dusun untuk menampilkan kandidat

+
+ @endforelse
-
- Catatan: - Kandidat yang tampil di halaman ini adalah data warga yang berada pada tahap - sedang_validasi atau selesai. - Saat tombol Tetapkan Teratas ditekan, sistem otomatis: -
โ€ข memilih warga dengan probabilitas tertinggi sesuai kuota -
โ€ข menetapkan yang lolos menjadi disetujui -
โ€ข menetapkan yang tidak lolos menjadi ditolak -
+ {{-- PAGINATION --}} + @if(isset($candidates) && method_exists($candidates,'links') && $candidates->hasPages()) +
+ {{ $candidates->appends(request()->query())->links() }} +
+ @endif +
+ {{-- NOTE --}} +
+ Catatan: Kandidat yang tampil adalah data warga pada tahap + sedang_validasi atau selesai. + Saat tombol Tetapkan Teratas ditekan, sistem otomatis:
+ โ€ข memilih warga dengan probabilitas tertinggi sesuai kuota
+ โ€ข menetapkan yang lolos menjadi disetujui
+ โ€ข menetapkan yang tidak lolos menjadi ditolak
\ No newline at end of file diff --git a/resources/views/admin/laporan.blade.php b/resources/views/admin/laporan.blade.php index 7e810c0..dfd5b8c 100644 --- a/resources/views/admin/laporan.blade.php +++ b/resources/views/admin/laporan.blade.php @@ -1,90 +1,116 @@ - + +
+
+

Laporan Penerima BLT-DD

+

Kelurahan Ngerong โ€” warga yang telah ditetapkan sebagai penerima final

+
+
+
-
+ + + {{-- FLASH --}} @if(session('success'))
- - - + {{ session('success') }}
@endif @@ -99,52 +125,39 @@ $periodes = $laporans->pluck('periode_bantuan')->filter()->unique()->count(); @endphp + {{-- STAT CARDS --}}
- - - +
{{ $totalPenerima }}
Total Penerima
-
- - - +
-
Rp {{ number_format($totalBantuan, 0, ',', '.') }}
-
Total Dana Tersalurkan
+
Rp {{ number_format($totalBantuan,0,',','.') }}
+
Total Dana
-
- - - +
-
{{ number_format($avgProb, 1) }}%
-
Rata-rata Probabilitas
+
{{ number_format($avgProb,1) }}%
+
Rata-rata Prob
-
- - - +
{{ $periodes }}
Periode Aktif
+ {{-- EKSPOR --}}
@@ -152,24 +165,28 @@ Ekspor & Distribusi Data
-
- Unduh PDF - Unduh Excel - -
+ + + Unduh PDF + + + + Unduh Excel + + @csrf -
- - {{ $totalPenerima }} penerima terdaftar + {{ $totalPenerima }} penerima terdaftar
+ {{-- UPLOAD PDF PUBLIK --}}
@@ -177,14 +194,15 @@ class="exp-btn btn-send"> Upload PDF Laporan Publik
-
-
+ @csrf - -
@@ -192,24 +210,17 @@ class="exp-btn btn-send">
@foreach($laporanPubliks as $pdf)
-
+
{{ $pdf->judul }}
-
- Diupload: {{ $pdf->created_at->format('d-m-Y H:i') }} -
+
Diupload: {{ $pdf->created_at->format('d-m-Y H:i') }}
-
- + Lihat PDF - -
- @csrf - @method('DELETE') + + @csrf @method('DELETE')
@@ -220,6 +231,7 @@ class="exp-btn btn-pdf"
+ {{-- DAFTAR PENERIMA FINAL --}}
@@ -229,6 +241,7 @@ class="exp-btn btn-pdf" {{ $totalPenerima }} data
+ {{-- DESKTOP TABLE --}}
@@ -243,109 +256,179 @@ class="exp-btn btn-pdf" - + - + - + - + @forelse($laporans as $index => $item) @php $nama = $item->nama_lengkap ?? '-'; - $init = strtoupper(substr($nama, 0, 1)); + $init = strtoupper(substr($nama,0,1)); $prob = $item->probability ?? 0; - if ($prob <= 1) $prob = $prob * 100; - - $sc = $prob >= 70 ? '#10b981' : ($prob >= 40 ? '#f59e0b' : '#f43f5e'); - $scBg = $prob >= 70 ? '#f0fdf4' : ($prob >= 40 ? '#fffbeb' : '#fff1f2'); - $scBd = $prob >= 70 ? '#bbf7d0' : ($prob >= 40 ? '#fde68a' : '#fecdd3'); - - $bantuanLain = strtolower($item->bantuan_lain ?? 'tidak'); + if($prob<=1) $prob=$prob*100; + $sc = $prob>=70?'#10b981':($prob>=40?'#f59e0b':'#f43f5e'); + $scBg = $prob>=70?'#f0fdf4':($prob>=40?'#fffbeb':'#fff1f2'); + $scBd = $prob>=70?'#bbf7d0':($prob>=40?'#fde68a':'#fecdd3'); @endphp - - - + - - - - + + + + + + + + - - - - - - - - - - - + - - - - - + + + @empty - - - + @endforelse
Penghasilan Tanggungan AsetBantuan LainBantuan UsiaProbabilitasProb StatusTgl PenetapanPenetapan PeriodeJumlah BantuanJumlah
{{ $index + 1 }}{{ $index+1 }} -
+
{{ $init }}
- {{ $nama }} + {{ $nama }}
{{ $item->nik ?? '-' }}{{ $item->no_kk ?? '-' }}{{ $item->nik??'-' }}{{ $item->no_kk??'-' }}RT {{ str_pad($item->nomor_rt??'0',3,'0',STR_PAD_LEFT) }}{{ $item->nama_dusun??'-' }}{{ $item->pekerjaan??'-' }}Rp {{ number_format($item->penghasilan??0,0,',','.') }}{{ $item->jumlah_tanggungan??0 }}{{ $item->aset_kepemilikan??'-' }} - - RT {{ str_pad($item->nomor_rt ?? '0', 3, '0', STR_PAD_LEFT) }} - - {{ $item->nama_dusun ?? '-' }}{{ $item->pekerjaan ?? '-' }}Rp {{ number_format($item->penghasilan ?? 0, 0, ',', '.') }}{{ $item->jumlah_tanggungan ?? 0 }}{{ $item->aset_kepemilikan ?? '-' }} - @if($bantuanLain === 'ya') + @if(strtolower($item->bantuan_lain??'')=='ya') Ya @else Tidak @endif {{ $item->usia ?? 0 }}{{ $item->usia??0 }}
-
-
-
- {{ number_format($prob, 1) }}% +
+ {{ number_format($prob,1) }}%
- {{ ucfirst($item->status_verifikasi ?? '-') }} + {{ ucfirst($item->status_verifikasi??'-') }} {{ $item->tanggal_penetapan?->format('d-m-Y') ?? '-' }}{{ $item->periode_bantuan ?? '-' }}Rp {{ number_format($item->jumlah_bantuan ?? 300000, 0, ',', '.') }}{{ $item->tanggal_penetapan?->format('d-m-Y')??'-' }}{{ $item->periode_bantuan??'-' }}Rp {{ number_format($item->jumlah_bantuan??300000,0,',','.') }}
-
-
- - - -
-

Belum ada data penerima final

-
-
+
+
+

Belum ada data penerima final

+
+
-
- SiBantuDes ยท Kelurahan Ngerong + {{-- MOBILE CARD LIST --}} +
+ @forelse($laporans as $index => $item) + @php + $nama = $item->nama_lengkap ?? '-'; + $init = strtoupper(substr($nama,0,1)); + $prob = $item->probability ?? 0; + if($prob<=1) $prob=$prob*100; + $sc = $prob>=70?'#10b981':($prob>=40?'#f59e0b':'#f43f5e'); + $scBg = $prob>=70?'#f0fdf4':($prob>=40?'#fffbeb':'#fff1f2'); + $scBd = $prob>=70?'#bbf7d0':($prob>=40?'#fde68a':'#fecdd3'); + @endphp +
+ {{-- Header --}} +
+
{{ $index+1 }}
+
{{ $init }}
+
{{ $nama }}
+
+ + {{-- NIK & KK --}} +
+
+ NIK + {{ $item->nik??'-' }} +
+
+ No KK + {{ $item->no_kk??'-' }} +
+
+ + {{-- Grid info --}} +
+
+ RT + RT {{ str_pad($item->nomor_rt??'0',3,'0',STR_PAD_LEFT) }} +
+
+ Dusun + {{ $item->nama_dusun??'-' }} +
+
+ Pekerjaan + {{ $item->pekerjaan??'-' }} +
+
+ Usia + {{ $item->usia??0 }} thn +
+
+ Penghasilan + Rp {{ number_format($item->penghasilan??0,0,',','.') }} +
+
+ Tanggungan + {{ $item->jumlah_tanggungan??0 }} orang +
+
+ Aset + {{ $item->aset_kepemilikan??'-' }} +
+
+ Bantuan Lain + @if(strtolower($item->bantuan_lain??'')=='ya') + Ya + @else + Tidak + @endif +
+
+ + {{-- Bottom: prob + status + jumlah bantuan --}} +
+
+
+ {{ number_format($prob,1) }}% +
+ + {{ ucfirst($item->status_verifikasi??'-') }} + + + Rp {{ number_format($item->jumlah_bantuan??300000,0,',','.') }} + +
+ + {{-- Periode & penetapan --}} +
+ Periode: {{ $item->periode_bantuan??'-' }} + • Penetapan: {{ $item->tanggal_penetapan?->format('d-m-Y')??'-' }} +
+
+ @empty +
+
+

Belum ada data penerima final

+
+ @endforelse
+ +
SiBantuDes ยท Kelurahan Ngerong
-
- - \ No newline at end of file + \ No newline at end of file diff --git a/resources/views/auth/forgot-password.blade.php b/resources/views/auth/forgot-password.blade.php index cb32e08..b3bbd20 100644 --- a/resources/views/auth/forgot-password.blade.php +++ b/resources/views/auth/forgot-password.blade.php @@ -1,25 +1,650 @@ -
- {{ __('Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.') }} + + +
+
+ + + +
Reset Password
+
Lupa Password?
+
Masukkan email yang terdaftar untuk memulai reset password.
+ + {{-- Step indicator --}} +
+
+
1
+
Verifikasi
+
+
+
+
2
+
Password Baru
+
+
+
+
3
+
Selesai
+
+
+ + {{-- Alert area --}} +
+ + {{-- SERVER-SIDE ERRORS --}} + @if($errors->any()) +
+ + + + {{ $errors->first() }} +
+ @endif + + {{-- โ•โ•โ• STEP 1: Verifikasi Email โ•โ•โ• --}} +
+
+ +
+
+ + + +
+ +
+
+
+ + +
+ + {{-- โ•โ•โ• STEP 2: Input Password Baru โ•โ•โ• --}} +
+
+ +
+
+ + + +
+ + +
+
+
+
+
+
+
+
+
+ +
+ +
+
+ + + +
+ + +
+
+
+ + +
+ + {{-- โ•โ•โ• STEP 3: Selesai โ•โ•โ• --}} +
+
+ + + +
+

Password Berhasil Diubah!

+

Password akun Anda sudah diperbarui. Silakan login menggunakan password baru.

+ + + + + Kembali ke Login + +
+ + + +
- - + + \ No newline at end of file diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 6eecab2..2b6ee37 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -1,4 +1,3 @@ - @@ -9,6 +8,7 @@ +
- + {{-- โ”€โ”€ LEFT PANEL โ”€โ”€ --}}
-
+
- + Logo SiBantuDes
SiBantuDes
Sistem Bantuan Tunai Desa
@@ -358,9 +439,11 @@ Kelurahan Ngerong
+
- Penyaluran Bantuan
yang Transparan
& Akuntabel + Penyaluran Bantuan
yang Transparan
& Akuntabel
+
@@ -384,16 +467,24 @@
- Laporan & monitoring penyaluran bantuan + Laporan & monitoring penyaluran bantuan
-
- + {{-- โ”€โ”€ RIGHT PANEL โ”€โ”€ --}}
+ + {{-- Tombol kembali ke landing page --}} + + + + + Kembali ke Beranda + +
BLT-DD • Kelurahan Ngerong
Selamat Datang
@@ -401,19 +492,18 @@
@if($errors->any()) -
- - - - {{ $errors->first() }} -
+
+ + + + {{ $errors->first() }} +
@endif
@csrf -
@@ -423,13 +513,10 @@ d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/>
- +
-
@@ -439,8 +526,7 @@ d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/>
- +
-
@@ -466,11 +551,14 @@ Daftar sebagai RT
+ +
-
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 491d94f..7669788 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -1,128 +1,292 @@ - - - - + + + + + {{ config('app.name', 'Laravel') }} + + + + @vite(['resources/css/app.css', 'resources/js/app.js']) + + + - - Filterisasi - + +
+
+
- - Laporan - + @php $role = Auth::user()->role ?? null; @endphp - @else - - Dashboard - - - - Pendataan - - - - Riwayat - - - - Laporan - - @endif - -
- -
-
- - {{ strtoupper(substr(Auth::user()->name ?? 'U', 0, 1)) }} - -
- -
- {{ Auth::user()->name ?? '' }} -
- - - @csrf - - -
+ + + +
+
+
{{ strtoupper(substr(Auth::user()->name ?? 'U', 0, 1)) }}
+ {{ Auth::user()->name ?? '' }}
+
+ @csrf + +
+
- - @isset($header) -
-
- {{ $header }} -
-
- @endisset - -
-
-
- {{ $slot }} -
-
-
- +
+ + + @isset($header) + + @endisset + + +
{{ $slot }}
+ + + \ No newline at end of file diff --git a/resources/views/layouts/guest.blade.php b/resources/views/layouts/guest.blade.php index 11feb47..bd24052 100644 --- a/resources/views/layouts/guest.blade.php +++ b/resources/views/layouts/guest.blade.php @@ -1,30 +1,40 @@ - - - - + + + + - {{ config('app.name', 'Laravel') }} + + SiBantuDes - - - + + + - - @vite(['resources/css/app.css', 'resources/js/app.js']) - - -
-
- - - -
+ + @vite(['resources/css/app.css', 'resources/js/app.js']) + -
- {{ $slot }} -
+ + + +
+ + + + +
+ {{ $slot }} +
+ +
+ + + \ No newline at end of file diff --git a/resources/views/rt/calon-penerima/create.blade.php b/resources/views/rt/calon-penerima/create.blade.php index 548edcb..9d9dd1e 100644 --- a/resources/views/rt/calon-penerima/create.blade.php +++ b/resources/views/rt/calon-penerima/create.blade.php @@ -6,7 +6,22 @@
- {{-- TAMPILKAN ERROR VALIDASI --}} + + @if ($errors->any())
Gagal menyimpan:
@@ -18,31 +33,29 @@
@endif - {{-- TAMPILKAN ERROR DARI TRY-CATCH CONTROLLER --}} @if (session('error'))
{{ session('error') }}
@endif - {{-- TAMPILKAN SUCCESS --}} @if (session('success'))
{{ session('success') }}
@endif -
+ @csrf {{-- SECTION 1: Data Identitas --}}
-
+

Data Identitas

-
+
@php $myRtId = auth()->user()->rt_id ?? (auth()->user()->rt->id ?? null); @endphp @@ -51,8 +64,6 @@ - - {{-- tampilkan tapi terkunci --}} + placeholder="16 digit No. KK" required inputmode="numeric">
- {{-- NIK --}}
- + placeholder="16 digit NIK" required inputmode="numeric">
- {{-- NAMA --}}
- + placeholder="Nama sesuai KTP" required>
- {{-- JENIS KELAMIN --}}
-
- {{-- TEMPAT LAHIR --}}
- + placeholder="Kota/Kabupaten" required>
- {{-- TANGGAL LAHIR --}}
- + required>
- {{-- USIA --}}
- + placeholder="Otomatis dari tanggal lahir" required inputmode="numeric">
- {{-- STATUS PERKAWINAN --}}
- @@ -210,25 +172,19 @@ class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 text-sm fo {{-- SECTION 2: Data Tempat Tinggal --}}
-
+

Data Tempat Tinggal

-
- {{-- ALAMAT --}} +
- + placeholder="Jalan, nomor rumah, RT/RW" required>
@@ -240,108 +196,69 @@ class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 text-sm fo - - {{-- tampilkan tapi terkunci --}} - - - {{-- yang dikirim --}} + value="{{ $myDusunName }}" readonly> -
- {{-- ASET --}}
- + placeholder="Misal: Rumah, Motor, dll" required>
{{-- SECTION 3: Data Ekonomi --}} -
-
+
+

Data Ekonomi

-
- {{-- PEKERJAAN --}} +
- + placeholder="Jenis pekerjaan" required>
- {{-- PENGHASILAN --}}
- + placeholder="0" required inputmode="decimal">
- {{-- JUMLAH TANGGUNGAN --}}
- + placeholder="Jumlah orang" required inputmode="numeric">
- {{-- BANTUAN LAIN --}}
- @@ -349,18 +266,112 @@ class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 text-sm fo
+ {{-- SECTION 4: Kondisi Tempat Tinggal --}} +
+
+
+

Kondisi Tempat Tinggal

+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + {{-- SECTION 5: Upload Dokumen & Foto --}} +
+
+
+

Upload Dokumen & Foto

+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ {{-- ACTIONS --}} -
- +
+ Batal -
@@ -431,7 +442,6 @@ function showToast(msg) { }); }); - // Auto-isi usia dari tanggal lahir document.getElementById('tanggal_lahir')?.addEventListener('change', function () { const dob = new Date(this.value); const today = new Date(); @@ -444,7 +454,6 @@ function showToast(msg) { } }); - // Submit validation document.getElementById('formPendataan').addEventListener('submit', function (e) { let valid = true; Object.keys(rules).forEach(id => { diff --git a/resources/views/rt/calon-penerima/edit.blade.php b/resources/views/rt/calon-penerima/edit.blade.php index 1dc8afd..c7e028c 100644 --- a/resources/views/rt/calon-penerima/edit.blade.php +++ b/resources/views/rt/calon-penerima/edit.blade.php @@ -1,6 +1,6 @@ -
+

Edit Pendataan Warga

Perbarui data dengan benar sebelum menyimpan.

@@ -15,6 +15,47 @@ class="inline-flex items-center gap-1.5 px-4 py-2 bg-white border border-gray-20
+ + {{-- ERROR VALIDASI --}} @if ($errors->any())
@@ -35,103 +76,93 @@ class="inline-flex items-center gap-1.5 px-4 py-2 bg-white border border-gray-20 @csrf @method('PUT') - - {{-- hidden aman, walau nanti tetap di-override controller --}} {{-- SECTION 1: Data Identitas --}}
-
+

Data Identitas

-
+
- {{-- RT (readonly) --}}

RT mengikuti akun RT yang sedang login.

- {{-- NO KK --}}
+ class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-gray-50" + placeholder="16 digit No. KK" required inputmode="numeric">
- {{-- NIK --}}
+ class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-gray-50" + placeholder="16 digit NIK" required inputmode="numeric">
- {{-- NAMA --}}
- {{-- JENIS KELAMIN --}}
- {{-- TEMPAT LAHIR --}}
- {{-- TANGGAL LAHIR --}}
- {{-- USIA --}}
+ class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-gray-50" + placeholder="Tahun" required inputmode="numeric">
- {{-- STATUS PERKAWINAN --}}
- {{-- DUSUN (readonly) --}}

Dusun mengikuti RT dan tidak dapat diubah.

@@ -174,7 +205,7 @@ class="w-full border border-gray-200 rounded-xl px-3 py-2 text-sm bg-gray-100 te
@@ -184,17 +215,17 @@ class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 text-sm fo {{-- SECTION 3: Data Ekonomi --}}
-
+

Data Ekonomi

-
+
@@ -203,8 +234,8 @@ class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 text-sm fo + class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-gray-50" + placeholder="0" required inputmode="decimal">
@@ -212,15 +243,15 @@ class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 text-sm fo + class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent bg-gray-50" + placeholder="Jumlah orang" required inputmode="numeric">
@@ -230,9 +261,9 @@ class="input-field w-full border border-gray-200 rounded-xl px-3 py-2 text-sm fo
{{-- ACTIONS --}} -
+
+ class="inline-flex items-center gap-1.5 px-5 py-2 text-sm font-medium bg-white border border-gray-200 text-gray-600 rounded-xl hover:bg-gray-50 transition"> Batal + +
+ @csrf @method('DELETE') + +
+ @endif +
+
+ @empty +
+
+ +
+

Belum ada data calon penerima

+ + Tambah sekarang +
+ @endforelse +
+
{{ $calonPenerimas->links() }}
diff --git a/resources/views/rt/calon-penerima/show.blade.php b/resources/views/rt/calon-penerima/show.blade.php index 1be2896..d5c0361 100644 --- a/resources/views/rt/calon-penerima/show.blade.php +++ b/resources/views/rt/calon-penerima/show.blade.php @@ -1,21 +1,21 @@ -
-
+
+
+ style="width:32px; height:32px; display:flex; align-items:center; justify-content:center; border-radius:10px; background:#fff; border:1.5px solid #e5e7eb; color:#6b7280; text-decoration:none; flex-shrink:0;"> -
-

Detail Calon Penerima

+
+

Detail Calon Penerima

Data pendataan warga & hasil prediksi kelayakan

@if(($calonPenerima->tracking_status ?? 'draft') === 'draft') + style="display:inline-flex; align-items:center; gap:6px; padding:7px 14px; background:#2563eb; color:#fff; font-size:12px; font-weight:700; border-radius:10px; text-decoration:none; box-shadow:0 2px 8px rgba(37,99,235,.25); flex-shrink:0;"> @@ -26,31 +26,96 @@ @php @@ -82,7 +147,6 @@ }; @endphp - {{-- FLASH --}} @if(session('success'))
@@ -96,53 +160,57 @@
@endif - {{-- BANNER --}} -
+ {{-- โ•โ• BANNER โ•โ• --}} +
-
- {{ strtoupper(substr($calonPenerima->nama_lengkap ?? 'U', 0, 1)) }} -
- -
-

{{ $calonPenerima->nama_lengkap ?? '-' }}

-

NIK: {{ $calonPenerima->nik ?? '-' }}

-
- - - {{ $trackingLabel }} - +
+ {{-- Avatar --}} +
+ {{ strtoupper(substr($calonPenerima->nama_lengkap ?? 'U', 0, 1)) }}
-
-
- @if($probPct !== null) -
-
{{ number_format($probPct,0) }}%
-
probabilitas
+ {{-- Nama + NIK + status --}} +
+

{{ $calonPenerima->nama_lengkap ?? '-' }}

+

NIK: {{ $calonPenerima->nik ?? '-' }}

+
+ + + {{ $trackingLabel }} +
- @endif +
- @if($tracking === 'selesai') - @if($st === 'disetujui') - Diterima - @elseif($st === 'ditolak') - Tidak Diterima - @else - Menunggu Hasil + {{-- Probabilitas + pill status --}} +
+ @if($probPct !== null) +
+
{{ number_format($probPct,0) }}%
+
probabilitas
+
@endif - @else - {{ $trackingLabel }} - @endif + @if($tracking === 'selesai') + @if($st === 'disetujui') + Diterima + @elseif($st === 'ditolak') + Tidak Diterima + @else + Menunggu Hasil + @endif + @else + {{ $trackingLabel }} + @endif +
- {{-- MAIN GRID --}} -
+ {{-- โ•โ• MAIN GRID โ•โ• --}} +
- {{-- KIRI --}} -
+ {{-- โ”€โ”€ KIRI โ”€โ”€ --}} +
{{-- Identitas --}} @@ -150,7 +218,7 @@

Identitas

-

No. KK

{{ $calonPenerima->no_kk ?? '-' }}

+

No. KK

{{ $calonPenerima->no_kk ?? '-' }}

Jenis Kelamin

{{ $calonPenerima->jenis_kelamin ?? '-' }}

Tempat Lahir

{{ $calonPenerima->tempat_lahir ?? '-' }}

Tanggal Lahir

{{ $calonPenerima->tanggal_lahir ? \Carbon\Carbon::parse($calonPenerima->tanggal_lahir)->translatedFormat('d F Y') : '-' }}

@@ -173,6 +241,11 @@

Aset Kepemilikan

{{ $calonPenerima->aset_kepemilikan ?? '-' }}

+
+

Kondisi Rumah

{{ $calonPenerima->kondisi_rumah ?? '-' }}

+

Meteran Listrik

{{ $calonPenerima->meteran_listrik ?? '-' }}

+

Sumber Air

{{ $calonPenerima->sumber_air ?? '-' }}

+
@@ -197,7 +270,56 @@
- {{-- Tracking Pengajuan --}} + {{-- Dokumen & Foto --}} + @php + $fotoFields = [ + 'foto_rumah_depan' => 'Foto Rumah Depan', + 'foto_rumah_belakang' => 'Foto Rumah Belakang', + 'foto_rumah_kanan' => 'Foto Rumah Kanan', + 'foto_rumah_kiri' => 'Foto Rumah Kiri', + 'foto_kk' => 'Foto KK', + 'foto_ktp' => 'Foto KTP', + 'foto_rekening_listrik' => 'Rekening Listrik', + 'foto_meteran_air' => 'Foto Meteran Air', + 'dokumen_pendukung' => 'Dokumen Pendukung', + ]; + $adaFoto = false; + foreach($fotoFields as $field => $label) { + if($calonPenerima->$field) { $adaFoto = true; break; } + } + @endphp + @if($adaFoto) +
+ @endif + + {{-- Tracking --}}

Tracking Pengajuan

@@ -210,7 +332,6 @@
-
2
@@ -225,7 +346,6 @@
-
3
@@ -240,7 +360,6 @@
-
4
@@ -261,40 +380,42 @@ {{-- Status Pengajuan --}}

Status Pengajuan

-
- @if($tracking === 'draft') - Draft - @elseif($tracking === 'terkirim') - Terkirim ke Kelurahan - @elseif($tracking === 'sedang_validasi') - Sedang Divalidasi - @elseif($tracking === 'selesai') - @if($st === 'disetujui') - Diterima - @elseif($st === 'ditolak') - Tidak Diterima - @else - Menunggu Hasil +
+
+ @if($tracking === 'draft') + Draft + @elseif($tracking === 'terkirim') + Terkirim ke Kelurahan + @elseif($tracking === 'sedang_validasi') + Sedang Divalidasi + @elseif($tracking === 'selesai') + @if($st === 'disetujui') + Diterima + @elseif($st === 'ditolak') + Tidak Diterima + @else + Menunggu Hasil + @endif @endif - @endif -
-

Dibuat

{{ $calonPenerima->created_at ? \Carbon\Carbon::parse($calonPenerima->created_at)->translatedFormat('d M Y, H:i') : '-' }}

-

Diperbarui

{{ $calonPenerima->updated_at ? \Carbon\Carbon::parse($calonPenerima->updated_at)->translatedFormat('d M Y, H:i') : '-' }}

-
- - @if(!empty($calonPenerima->catatan_admin)) -
- Catatan: {{ $calonPenerima->catatan_admin }} +
+

Dibuat

{{ $calonPenerima->created_at ? \Carbon\Carbon::parse($calonPenerima->created_at)->translatedFormat('d M Y, H:i') : '-' }}

+

Diperbarui

{{ $calonPenerima->updated_at ? \Carbon\Carbon::parse($calonPenerima->updated_at)->translatedFormat('d M Y, H:i') : '-' }}

- @endif + + @if(!empty($calonPenerima->catatan_admin)) +
+ Catatan: {{ $calonPenerima->catatan_admin }} +
+ @endif +
-
+
{{-- end kiri --}} - {{-- KANAN --}} -
+ {{-- โ”€โ”€ KANAN (sidebar) โ”€โ”€ --}} +
{{-- Prediksi --}}
@@ -311,7 +432,7 @@ {{ number_format($probPct,0) }}%
-
+

Rekomendasi

{{ $rec }}
@@ -338,8 +459,18 @@ Penjelasan Lengkap
- @foreach(['Pekerjaan'=>$calonPenerima->pekerjaan??'-','Penghasilan'=>'Rp '.number_format((float)($calonPenerima->penghasilan??0),0,',','.'),'Tanggungan'=>($calonPenerima->jumlah_tanggungan??'-').' orang','Aset'=>$calonPenerima->aset_kepemilikan??'-','Bantuan Lain'=>ucfirst($calonPenerima->bantuan_lain??'-'),'Usia'=>($calonPenerima->usia??'-').' tahun'] as $lbl=>$val) -
{{ $lbl }}{{ $val }}
+ @foreach([ + 'Pekerjaan' => $calonPenerima->pekerjaan??'-', + 'Penghasilan' => 'Rp '.number_format((float)($calonPenerima->penghasilan??0),0,',','.'), + 'Tanggungan' => ($calonPenerima->jumlah_tanggungan??'-').' orang', + 'Aset' => $calonPenerima->aset_kepemilikan??'-', + 'Bantuan Lain' => ucfirst($calonPenerima->bantuan_lain??'-'), + 'Usia' => ($calonPenerima->usia??'-').' tahun', + 'Kondisi Rumah' => $calonPenerima->kondisi_rumah??'-', + 'Meteran Listrik'=> $calonPenerima->meteran_listrik??'-', + 'Sumber Air' => $calonPenerima->sumber_air??'-', + ] as $lbl=>$val) +
{{ $lbl }}{{ $val }}
@endforeach
@if(!empty($explanation['positive'])) @@ -415,7 +546,8 @@
@endif -
-
+
{{-- end kanan --}} + +
{{-- end .mg --}} \ No newline at end of file diff --git a/resources/views/rt/dashboard.blade.php b/resources/views/rt/dashboard.blade.php index f8a831c..eb84945 100644 --- a/resources/views/rt/dashboard.blade.php +++ b/resources/views/rt/dashboard.blade.php @@ -1,238 +1,220 @@ -
+
-

Dashboard

+

Dashboard

- Ringkasan data pendataan warga {{ Auth::user()->rt->dusun->nama_dusun ?? '' }} + Pendataan warga {{ Auth::user()->rt->dusun->nama_dusun ?? '' }}

-
- +
+ - - {{ \Carbon\Carbon::now('Asia/Jakarta')->translatedFormat('l, d F Y') }} - โ€” - {{ \Carbon\Carbon::now('Asia/Jakarta')->format('H:i') }} WIB - + {{ \Carbon\Carbon::now('Asia/Jakarta')->translatedFormat('l, d F Y') }} โ€” {{ \Carbon\Carbon::now('Asia/Jakarta')->format('H:i') }} WIB
- @php $avgProb = \App\Models\PrediksiKelayakan::whereHas('calonPenerima', function ($q) { $q->where('user_id', Auth::id()); - })->avg('probability'); - - $avgProb = $avgProb ?? 0; - - if ($avgProb <= 1) { - $avgProb = $avgProb * 100; - } + })->avg('probability') ?? 0; + if ($avgProb <= 1) $avgProb = $avgProb * 100; @endphp
- {{-- GREETING (asli tidak diubah) --}} -
+ {{-- GREETING --}} +
{{ strtoupper(substr(Auth::user()->name ?? 'U', 0, 1)) }}
-
-

- Selamat datang, {{ Auth::user()->name ?? 'Pengguna' }} ๐Ÿ‘‹ -

+
+

Selamat datang, {{ Auth::user()->name ?? 'Pengguna' }} ๐Ÿ‘‹

Berikut ringkasan data terkini yang perlu Anda pantau.

- {{-- STAT CARDS (asli tidak diubah) --}} -
+ {{-- STAT CARDS --}} +
-
+ @php + $rtCards = [ + ['label'=>'Total Warga','val'=>$stats['total_input'],'grad'=>'#2563eb,#1d4ed8','shadow'=>'rgba(37,99,235,.3)','tc'=>'rgba(191,219,254,.9)','icon'=>'M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z'], + ['label'=>'Pending','val'=>$stats['pending'],'grad'=>'#f59e0b,#d97706','shadow'=>'rgba(245,158,11,.3)','tc'=>'rgba(254,243,199,.9)','icon'=>'M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z'], + ['label'=>'Diterima','val'=>$stats['disetujui'],'grad'=>'#10b981,#059669','shadow'=>'rgba(16,185,129,.3)','tc'=>'rgba(167,243,208,.9)','icon'=>'M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z'], + ['label'=>'Ditolak','val'=>$stats['ditolak'],'grad'=>'#f43f5e,#e11d48','shadow'=>'rgba(244,63,94,.3)','tc'=>'rgba(254,205,211,.9)','icon'=>'M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z'], + ]; + @endphp + + @foreach($rtCards as $c) +
-

Total Warga

-

{{ $stats['total_input'] }}

+

{{ $c['label'] }}

+

{{ $c['val'] }}

-
- -
-
- -
-
-
-

Pending

-

{{ $stats['pending'] }}

-
-
- -
-
- -
-
-
-

Diterima

-

{{ $stats['disetujui'] }}

-
-
- -
-
- -
-
-
-

Ditolak

-

{{ $stats['ditolak'] }}

-
-
- +
+
+ @endforeach
- {{-- GRID: Pendataan Terbaru + Aksi Cepat (logika asli 100% tidak diubah) --}} -
+ {{-- GRID: Terbaru + Aksi --}} +
{{-- Pendataan Terbaru --}}
-
+
-
+

Pendataan Terbaru

- - - Live + + Live
-
@forelse($recentCalonPenerima as $calon) -
-
-
- {{ strtoupper(substr($calon->nama_lengkap, 0, 1)) }} -
-
-

{{ $calon->nama_lengkap }}

-

NIK: {{ $calon->nik }}

-
+
+
+
+ {{ strtoupper(substr($calon->nama_lengkap,0,1)) }}
-
- @if($calon->status_verifikasi == 'pending') - - - Pending - - @elseif($calon->status_verifikasi == 'disetujui') - - - Disetujui - - @else - - - {{ ucfirst($calon->status_verifikasi) }} - - @endif -

{{ $calon->created_at->diffForHumans() }}

+
+

{{ $calon->nama_lengkap }}

+

{{ $calon->nik }}

+
+ @php + $sv=['pending'=>['#fffbeb','#b45309','#fde68a','Pending'],'disetujui'=>['#f0fdf4','#166534','#bbf7d0','Disetujui']]; + $sv=$sv[$calon->status_verifikasi]??['#fff1f2','#be123c','#fecdd3',ucfirst($calon->status_verifikasi)]; + @endphp + + {{ $sv[3] }} + +

{{ $calon->created_at->diffForHumans() }}

+
+
@empty -
-
- -
-

Belum ada data pendataan

-
+
+

Belum ada data pendataan

+
@endforelse
- {{-- Aksi Cepat (asli tidak diubah) --}} + {{-- Aksi Cepat --}}
-
-
+
+

Aksi Cepat

+
-
- - {{-- Daftarkan Warga Baru (asli) --}} - +
-
-

Daftarkan Warga Baru

+
+

Daftarkan Warga Baru

Tambah data calon penerima

- {{-- Lihat Laporan (asli) --}} - +
-
-

Lihat Laporan

-

Lihat hasil akhir yang dikirim admin

+
+

Lihat Laporan

+

Hasil akhir dari admin

- {{-- Rata-rata skor (asli, $avgProb tidak diubah) --}} -
-
-
+ {{-- Skor rata-rata --}} +
+
-
-

Rata-rata Skor Kelayakan

- -
-

- {{ number_format($avgProb, 1) }}% +

Rata-rata Skor Kelayakan

+

+ {{ number_format($avgProb,1) }}%

-
+

- Nilai rata-rata prediksi kelayakan, bukan keputusan akhir bantuan + Rata-rata prediksi, bukan keputusan akhir

@@ -244,11 +226,4 @@ function updateClock() {
- - \ No newline at end of file diff --git a/resources/views/rt/laporan.blade.php b/resources/views/rt/laporan.blade.php index ac6bea1..2502dba 100644 --- a/resources/views/rt/laporan.blade.php +++ b/resources/views/rt/laporan.blade.php @@ -1,111 +1,103 @@ - -/* Empty */ -.empty-state{padding:52px 16px;text-align:center;} -.empty-icon{width:46px;height:46px;background:#f1f5f9;border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 10px;} -.empty-icon svg{width:20px;height:20px;} - -/* Footer */ -.tbl-foot{padding:9px 18px;border-top:1.5px solid #f1f5f9;background:#fafbfc;text-align:center;} -.credit{font-size:11px;color:#cbd5e1;font-weight:500;} - - -
- - {{-- โ”€โ”€ HEADER โ”€โ”€ --}} -
-

- Laporan Hasil Kelayakan -

-

- Data hasil akhir verifikasi warga yang telah dikirim oleh admin kelurahan -

-
- - {{-- โ”€โ”€ SUMMARY โ”€โ”€ --}} @php - $total = $stats['total'] ?? $laporans->count(); - $diterima = $stats['diterima'] ?? $laporans->where('status_verifikasi', 'disetujui')->count(); - $ditolak = $stats['ditolak'] ?? $laporans->where('status_verifikasi', 'ditolak')->count(); + $total = $stats['total'] ?? $laporans->count(); + $diterima = $stats['diterima'] ?? $laporans->where('status_verifikasi','disetujui')->count(); + $ditolak = $stats['ditolak'] ?? $laporans->where('status_verifikasi','ditolak')->count(); @endphp + {{-- STAT CARDS --}}
- - - +
{{ $total }}
Total Warga
- - - +
{{ $diterima }}
Diterima
- - - +
{{ $ditolak }}
Ditolak
- {{-- โ”€โ”€ TABLE โ”€โ”€ --}} + {{-- TABLE CARD --}}
@@ -115,11 +107,12 @@ {{ $total }} data
+ {{-- DESKTOP TABLE --}}
- + @@ -137,113 +130,149 @@ @forelse($laporans as $i => $item) @php - $prob = $item->probability ?? 0; - if ($prob <= 1) $prob = $prob * 100; - + $prob = $item->probability ?? 0; + if($prob <= 1) $prob = $prob * 100; $nama = $item->nama_lengkap ?? '-'; - $init = strtoupper(substr($nama, 0, 1)); - $sc = $prob >= 70 ? '#10b981' : ($prob >= 40 ? '#f59e0b' : '#f43f5e'); - + $init = strtoupper(substr($nama,0,1)); + $sc = $prob>=70?'#10b981':($prob>=40?'#f59e0b':'#f43f5e'); $colors = ['#3b82f6','#8b5cf6','#ec4899','#f59e0b','#10b981','#ef4444','#06b6d4']; $avColor = $colors[ord($init) % count($colors)]; - - $diterima = $item->status_verifikasi === 'disetujui'; + $acc = ($item->status_verifikasi === 'disetujui'); @endphp - - + - - - + + + + + + + - - - - - - - - - - - - - - - + - @empty - - - + @endforelse
## Nama NIK RT
{{ $i + 1 }}{{ $i+1 }} -
+
{{ $init }}
-
-
{{ $nama }}
-
+ {{ $nama }}
{{ $item->nik ?? '-' }}{{ $item->nik??'-' }}RT {{ str_pad($item->nomor_rt??'-',3,'0',STR_PAD_LEFT) }}{{ $item->nama_dusun??'-' }}{{ $item->pekerjaan??'-' }}Rp {{ number_format($item->penghasilan??0,0,',','.') }}{{ $item->jumlah_tanggungan??'-' }}{{ $item->aset_kepemilikan??'-' }} - - RT {{ str_pad($item->nomor_rt ?? '-', 3, '0', STR_PAD_LEFT) }} - - - {{ $item->nama_dusun ?? '-' }} - {{ $item->pekerjaan ?? '-' }} - Rp {{ number_format($item->penghasilan ?? 0, 0, ',', '.') }} - - {{ $item->jumlah_tanggungan ?? '-' }} - {{ $item->aset_kepemilikan ?? '-' }} - @if(strtolower($item->bantuan_lain ?? '') === 'ya') + @if(strtolower($item->bantuan_lain??'')=='ya') Ya @else Tidak @endif {{ $item->usia ?? '-' }}{{ $item->usia??'-' }}
-
-
-
- - {{ number_format($prob, 1) }}% - +
+ {{ number_format($prob,1) }}%
- @if($diterima) - - - Diterima - + @if($acc) + Diterima @else - - - Ditolak - + Ditolak @endif
-
-
- - - -
-

Belum ada laporan yang dikirim admin

-
-
+
+
+

Belum ada laporan yang dikirim admin

+
+
-
- SiBantuDes · Kelurahan Ngerong + {{-- MOBILE CARD LIST --}} +
+ @forelse($laporans as $i => $item) + @php + $prob = $item->probability ?? 0; + if($prob <= 1) $prob = $prob * 100; + $nama = $item->nama_lengkap ?? '-'; + $init = strtoupper(substr($nama,0,1)); + $sc = $prob>=70?'#10b981':($prob>=40?'#f59e0b':'#f43f5e'); + $scBg = $prob>=70?'#f0fdf4':($prob>=40?'#fffbeb':'#fff1f2'); + $scBd = $prob>=70?'#bbf7d0':($prob>=40?'#fde68a':'#fecdd3'); + $colors = ['#3b82f6','#8b5cf6','#ec4899','#f59e0b','#10b981','#ef4444','#06b6d4']; + $avColor = $colors[ord($init) % count($colors)]; + $acc = ($item->status_verifikasi === 'disetujui'); + @endphp +
+
+
{{ $init }}
+
+
{{ $nama }}
+
{{ $item->nik??'-' }}
+
+ #{{ $i+1 }} +
+ +
+
+ RT + RT {{ str_pad($item->nomor_rt??'-',3,'0',STR_PAD_LEFT) }} +
+
+ Dusun + {{ $item->nama_dusun??'-' }} +
+
+ Pekerjaan + {{ $item->pekerjaan??'-' }} +
+
+ Usia + {{ $item->usia??'-' }} thn +
+
+ Penghasilan + Rp {{ number_format($item->penghasilan??0,0,',','.') }} +
+
+ Tanggungan + {{ $item->jumlah_tanggungan??'-' }} orang +
+
+ Aset + {{ $item->aset_kepemilikan??'-' }} +
+
+ Bantuan Lain + @if(strtolower($item->bantuan_lain??'')=='ya') + Ya + @else + Tidak + @endif +
+
+ +
+
+
+ {{ number_format($prob,1) }}% +
+ @if($acc) + Diterima + @else + Ditolak + @endif +
+
+ @empty +
+
+

Belum ada laporan yang dikirim admin

+
+ @endforelse
+ +
SiBantuDes ยท Kelurahan Ngerong
-
- \ No newline at end of file diff --git a/routes/auth.php b/routes/auth.php index 3926ecf..26b90ea 100644 --- a/routes/auth.php +++ b/routes/auth.php @@ -6,7 +6,6 @@ use App\Http\Controllers\Auth\EmailVerificationPromptController; use App\Http\Controllers\Auth\NewPasswordController; use App\Http\Controllers\Auth\PasswordController; -use App\Http\Controllers\Auth\PasswordResetLinkController; use App\Http\Controllers\Auth\RegisteredUserController; use App\Http\Controllers\Auth\VerifyEmailController; use Illuminate\Support\Facades\Route; @@ -22,17 +21,8 @@ Route::post('login', [AuthenticatedSessionController::class, 'store']); - Route::get('forgot-password', [PasswordResetLinkController::class, 'create']) - ->name('password.request'); - - Route::post('forgot-password', [PasswordResetLinkController::class, 'store']) - ->name('password.email'); - - Route::get('reset-password/{token}', [NewPasswordController::class, 'create']) - ->name('password.reset'); - - Route::post('reset-password', [NewPasswordController::class, 'store']) - ->name('password.store'); + /* forgot-password & reset-password dihapus dari sini, + sudah diganti dengan ManualPasswordResetController di web.php */ }); Route::middleware('auth')->group(function () { @@ -56,4 +46,4 @@ Route::post('logout', [AuthenticatedSessionController::class, 'destroy']) ->name('logout'); -}); +}); \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index bab1c61..b216505 100644 --- a/routes/web.php +++ b/routes/web.php @@ -18,6 +18,9 @@ use App\Http\Controllers\Rt\CalonPenerimaController as RtCalonPenerimaController; use App\Http\Controllers\Rt\LaporanController as RtLaporanController; +// Manual Password Reset +use App\Http\Controllers\Auth\ManualPasswordResetController; + /* |-------------------------------------------------------------------------- | ROOT / LANDING PAGE PUBLIK @@ -25,6 +28,23 @@ */ Route::get('/', [LandingPageController::class, 'index'])->name('landing'); +/* +|-------------------------------------------------------------------------- +| MANUAL PASSWORD RESET (guest only) +|-------------------------------------------------------------------------- +*/ +Route::get('/forgot-password', [ManualPasswordResetController::class, 'showForm']) + ->middleware('guest') + ->name('password.request'); + +Route::post('/password/manual/check', [ManualPasswordResetController::class, 'checkEmail']) + ->middleware('guest') + ->name('password.manual.check'); + +Route::post('/password/manual/update', [ManualPasswordResetController::class, 'updatePassword']) + ->middleware('guest') + ->name('password.manual.update'); + /* |-------------------------------------------------------------------------- | DASHBOARD UTAMA (redirect sesuai role)