diff --git a/WhatsApp Image 2026-02-04 at 19.00.08 (1).jpeg b/WhatsApp Image 2026-02-04 at 19.00.08 (1).jpeg deleted file mode 100644 index 427d727..0000000 Binary files a/WhatsApp Image 2026-02-04 at 19.00.08 (1).jpeg and /dev/null differ diff --git a/WhatsApp Image 2026-02-04 at 19.00.08.jpeg b/WhatsApp Image 2026-02-04 at 19.00.08.jpeg deleted file mode 100644 index 470a1c0..0000000 Binary files a/WhatsApp Image 2026-02-04 at 19.00.08.jpeg and /dev/null differ diff --git a/app/Http/Controllers.zip b/app/Http/Controllers.zip new file mode 100644 index 0000000..d6c391e Binary files /dev/null and b/app/Http/Controllers.zip differ diff --git a/app/Http/Controllers/Admin/AkunController.php b/app/Http/Controllers/Admin/AkunController.php index 4bb3984..f53642a 100644 --- a/app/Http/Controllers/Admin/AkunController.php +++ b/app/Http/Controllers/Admin/AkunController.php @@ -21,14 +21,14 @@ public function create() { $gurus = Guru::whereNull('user_id')->get(['id', 'nama_guru']); $waliMurids = WaliMurid::whereNull('user_id')->get(['id', 'nama_wali']); - + return view('admin.akun.create', compact('gurus', 'waliMurids')); } public function store(Request $request) { - + $request->validate([ 'role' => 'required|in:guru,wali_murid', 'user_guru_id' => 'required', @@ -43,22 +43,22 @@ public function store(Request $request) $name = $data->nama_wali; $email = $data->email ?? strtolower(str_replace(' ', '', $data->nama_wali)) . '@paud.local'; } - - + + if (User::where('email', $email)->exists()) { return back()->with('error', 'Email sudah digunakan untuk akun lain.'); } - + $user = User::create([ 'name' => $name, 'email' => $email, 'password' => Hash::make('123456'), 'role' => $request->role, ]); - + $data->update(['user_id' => $user->id]); - + return redirect()->route('akun.index')->with('success', 'Akun berhasil dibuat!'); } @@ -67,12 +67,12 @@ public function destroy(User $akun) $akun->delete(); return redirect()->route('akun.index')->with('success', 'Akun berhasil dihapus.'); } - + public function edit(User $akun) { return view('admin.akun.edit', compact('akun')); } - + public function update(Request $request, User $akun) { $request->validate([ @@ -80,22 +80,22 @@ public function update(Request $request, User $akun) 'email' => 'required|email|unique:users,email,' . $akun->id, 'role' => 'required|in:admin,guru,wali_murid', ]); - + $akun->update([ 'name' => $request->name, 'email' => $request->email, 'role' => $request->role, ]); - + return redirect()->route('akun.index')->with('success', 'Akun berhasil diperbarui.'); } - + public function resetPassword(User $akun) { $akun->update([ 'password' => Hash::make('123456'), ]); - + return redirect()->route('akun.index')->with('success', 'Password berhasil direset ke default (123456).'); } } diff --git a/app/Http/Controllers/Admin/GuruController.php b/app/Http/Controllers/Admin/GuruController.php index ea8be8c..5b0f8d7 100644 --- a/app/Http/Controllers/Admin/GuruController.php +++ b/app/Http/Controllers/Admin/GuruController.php @@ -23,74 +23,93 @@ public function create() } public function store(Request $request) - { - // 1. Validasi - $request->validate([ - 'nama_guru' => 'required', - 'email' => 'required|email|unique:users,email', - 'password' => 'required|min:6', + { + // 1. Validasi + $request->validate([ + 'nama_guru' => 'required', + 'email' => 'required|email|unique:users,email', + 'password' => 'required|min:6', + ]); + + DB::transaction(function () use ($request) { + + // A. SIMPAN KE TABEL USERS (Disini tempatnya Email & Password) + $user = User::create([ + 'name' => $request->nama_guru, + 'email' => $request->email, + 'password' => Hash::make($request->password), + 'role' => 'guru', ]); - - DB::transaction(function () use ($request) { - - // A. SIMPAN KE TABEL USERS (Disini tempatnya Email & Password) - $user = User::create([ - 'name' => $request->nama_guru, - 'email' => $request->email, - 'password' => Hash::make($request->password), - 'role' => 'guru', - ]); - - // B. SIMPAN KE TABEL GURU (HANYA DATA PROFIL) - Guru::create([ - 'user_id' => $user->id, - 'nama_guru' => $request->nama_guru, - 'nip' => $request->nip, - 'jenis_guru' => $request->jenis_guru, // Pastikan kolom ini ada di tabel guru kamu - 'no_hp' => $request->no_hp, - 'alamat' => $request->alamat, - - // ❌ JANGAN ADA baris 'email' => ... disini - // ❌ JANGAN ADA baris 'password' => ... disini - ]); - - }); - - return redirect()->route('guru.index')->with('success', 'Berhasil menambahkan Guru!'); - } + + // B. SIMPAN KE TABEL GURU (HANYA DATA PROFIL) + Guru::create([ + 'user_id' => $user->id, + 'nama_guru' => $request->nama_guru, + 'nip' => $request->nip, + 'jenis_guru' => $request->jenis_guru, // Pastikan kolom ini ada di tabel guru kamu + 'no_hp' => $request->no_hp, + 'alamat' => $request->alamat, + + // ❌ JANGAN ADA baris 'email' => ... disini + // ❌ JANGAN ADA baris 'password' => ... disini + ]); + + }); + + return redirect()->route('guru.index')->with('success', 'Berhasil menambahkan Guru!'); + } public function edit($id) - { - // PENTING: Tambahkan ->with('user') biar data email & nama akun ke-load - $guru = Guru::with('user')->findOrFail($id); - return view('admin.guru.edit', compact('guru')); - } - - public function update(Request $request, $id) - { - // Cari data guru - $guru = Guru::findOrFail($id); - - // 1. Validasi - $request->validate([ - 'nama_guru' => 'required|string|max:255', // Harus nama_guru - 'email' => 'required|email', - 'no_hp' => 'nullable|string', - 'jenis_guru' => 'required|string', - ]); - - // 2. Update Tabel Guru LANGSUNG - // Kita abaikan tabel user dulu karena user_id kamu masih NULL - $guru->update([ - 'nama_guru' => $request->nama_guru, // Masukkan ke kolom nama_guru - 'email' => $request->email, - 'no_hp' => $request->no_hp, - 'jenis_guru' => $request->jenis_guru, - ]); - - return redirect()->route('guru.index')->with('success', 'Data Guru berhasil diperbarui!'); + { + // PENTING: Tambahkan ->with('user') biar data email & nama akun ke-load + $guru = Guru::with('user')->findOrFail($id); + return view('admin.guru.edit', compact('guru')); + } + + public function update(Request $request, $id) + { + // Cari data guru + $guru = Guru::findOrFail($id); + + // 1. Validasi + $request->validate([ + 'nama_guru' => 'required|string|max:255', + 'email' => 'required|email|unique:users,email,' . $guru->user_id, + 'password' => 'nullable|min:6', + 'no_hp' => 'nullable|string', + 'jenis_guru' => 'required|string', + 'nip' => 'nullable|string', + 'alamat' => 'nullable|string', + ]); + + DB::transaction(function () use ($request, $guru) { + // Update User Login (jika ada) + if ($guru->user) { + $userData = [ + 'name' => $request->nama_guru, + 'email' => $request->email, + ]; + + if ($request->filled('password')) { + $userData['password'] = Hash::make($request->password); + } + + $guru->user->update($userData); } + // Update Tabel Guru LANGSUNG + $guru->update([ + 'nama_guru' => $request->nama_guru, + 'no_hp' => $request->no_hp, + 'jenis_guru' => $request->jenis_guru, + 'nip' => $request->nip, + 'alamat' => $request->alamat, + ]); + }); + + return redirect()->route('guru.index')->with('success', 'Data Guru berhasil diperbarui!'); + } + public function destroy(Guru $guru) { $guru->delete(); diff --git a/app/Http/Controllers/Admin/PengumumanController.php b/app/Http/Controllers/Admin/PengumumanController.php index d5af954..192754c 100644 --- a/app/Http/Controllers/Admin/PengumumanController.php +++ b/app/Http/Controllers/Admin/PengumumanController.php @@ -3,6 +3,7 @@ use App\Http\Controllers\Controller; use App\Models\Pengumuman; +use App\Models\User; use Illuminate\Http\Request; class PengumumanController extends Controller @@ -20,17 +21,33 @@ public function create() public function store(Request $request) { + // 1. Validasi Input $request->validate([ - 'judul' => 'required|string|max:255', - 'isi' => 'required|string', - 'tanggal_mulai' => 'nullable|date', + 'judul' => 'required|string|max:255', + 'isi' => 'required|string', + 'tanggal_mulai' => 'nullable|date', 'tanggal_selesai' => 'nullable|date|after_or_equal:tanggal_mulai', - 'status' => 'boolean', + 'status' => 'boolean', ]); - Pengumuman::create($request->all()); + // 2. Simpan Pengumuman ke Database + $pengumuman = Pengumuman::create($request->all()); - return redirect()->route('pengumuman.index')->with('success', 'Pengumuman berhasil ditambahkan.'); + // 3. Ambil semua FCM token user yang tidak null (guru & wali murid) + $tokens = User::whereNotNull('fcm_token')->pluck('fcm_token')->toArray(); + + // 4. Trigger Broadcast Notifikasi FCM + if (count($tokens) > 0) { + $notifTitle = "Pengumuman Baru: " . $pengumuman->judul; + $notifBody = "Ada pengumuman baru dari sekolah, yuk cek sekarang!"; + + // Panggil method dari Controller dasar + $this->sendFCMNotification($notifTitle, $notifBody, $tokens); + } + + // 5. Redirect dengan pesan sukses + return redirect()->route('pengumuman.index') + ->with('success', 'Pengumuman berhasil ditambahkan dan notifikasi telah dikirim.'); } public function edit(Pengumuman $pengumuman) diff --git a/app/Http/Controllers/Admin/PenjemputanController.php b/app/Http/Controllers/Admin/PenjemputanController.php index 4e34486..1083f7f 100644 --- a/app/Http/Controllers/Admin/PenjemputanController.php +++ b/app/Http/Controllers/Admin/PenjemputanController.php @@ -13,7 +13,7 @@ public function index() { // Ambil data penjemputan, urutkan dari yang paling baru (latest) $logs = Penjemputan::with('siswa')->latest('waktu_jemput')->get(); - + // Kirim ke tampilan return view('admin.penjemputan.index', compact('logs')); } diff --git a/app/Http/Controllers/Admin/PerkembanganController.php b/app/Http/Controllers/Admin/PerkembanganController.php index e60efe1..b8fd033 100644 --- a/app/Http/Controllers/Admin/PerkembanganController.php +++ b/app/Http/Controllers/Admin/PerkembanganController.php @@ -13,29 +13,29 @@ class PerkembanganController extends Controller { // Halaman Utama: Tampilkan Daftar Siswa public function index() - { - // PERBAIKAN: Ganti 'nama' menjadi 'nama_siswa' - $siswas = Siswa::orderBy('nama_siswa', 'asc')->get(); - - return view('admin.perkembangan.index', compact('siswas')); - } + { + // PERBAIKAN: Ganti 'nama' menjadi 'nama_siswa' + $siswas = Siswa::orderBy('nama_siswa', 'asc')->get(); + + return view('admin.perkembangan.index', compact('siswas')); + } // Halaman Detail: Tampilkan Rapot (Gabungan 3 Tabel) public function show($id) - { - $siswa = Siswa::findOrFail($id); - - // 1. Ambil Data Rapot (Untuk Tabel Bawah) - $rapots = \App\Models\Rapot::where('siswa_id', $id)->orderBy('created_at', 'desc')->get(); - - // 2. Ambil Data Harian (Untuk Tombol/Menu Atas) - SUDAH DIAKTIFKAN - $anekdots = \App\Models\Anekdot::where('siswa_id', $id)->get(); - $karyas = \App\Models\HasilKarya::where('siswa_id', $id)->get(); - $ceklis = \App\Models\PenilaianCeklis::where('siswa_id', $id)->get(); - - // Kirim semua variabel ke View - return view('admin.perkembangan.show', compact('siswa', 'rapots', 'anekdots', 'karyas', 'ceklis')); - } + { + $siswa = Siswa::findOrFail($id); + + // 1. Ambil Data Rapot (Untuk Tabel Bawah) + $rapots = \App\Models\Rapot::where('siswa_id', $id)->orderBy('created_at', 'desc')->get(); + + // 2. Ambil Data Harian (Untuk Tombol/Menu Atas) - SUDAH DIAKTIFKAN + $anekdots = \App\Models\Anekdot::where('siswa_id', $id)->get(); + $karyas = \App\Models\HasilKarya::where('siswa_id', $id)->get(); + $ceklis = \App\Models\PenilaianCeklis::where('siswa_id', $id)->get(); + + // Kirim semua variabel ke View + return view('admin.perkembangan.show', compact('siswa', 'rapots', 'anekdots', 'karyas', 'ceklis')); + } // Halaman Cetak (Opsional, logika sama dengan show) public function print($id) diff --git a/app/Http/Controllers/Admin/SiswaController.php b/app/Http/Controllers/Admin/SiswaController.php index 9d8adb0..d986340 100644 --- a/app/Http/Controllers/Admin/SiswaController.php +++ b/app/Http/Controllers/Admin/SiswaController.php @@ -25,31 +25,31 @@ public function create() public function store(Request $request) { $request->validate([ - 'nis' => 'required|unique:siswas,nis', - 'nisn' => 'nullable|string', - 'nama_siswa' => 'required|string|max:255', - 'tempat_lahir' => 'required|string', + 'nis' => 'required|unique:siswas,nis', + 'nisn' => 'nullable|string', + 'nama_siswa' => 'required|string|max:255', + 'tempat_lahir' => 'required|string', 'tanggal_lahir' => 'required|date', 'jenis_kelamin' => 'required|in:L,P', 'wali_murid_id' => 'required|exists:wali_murids,id', - + // --- TAMBAHAN BARU: Validasi Titik Koordinat Peta --- - 'latitude' => 'nullable|string', - 'longitude' => 'nullable|string', + 'latitude' => 'nullable|string', + 'longitude' => 'nullable|string', ]); Siswa::create([ - 'nis' => $request->nis, - 'nisn' => $request->nisn, - 'nama_siswa' => $request->nama_siswa, - 'tempat_lahir' => $request->tempat_lahir, + 'nis' => $request->nis, + 'nisn' => $request->nisn, + 'nama_siswa' => $request->nama_siswa, + 'tempat_lahir' => $request->tempat_lahir, 'tanggal_lahir' => $request->tanggal_lahir, 'jenis_kelamin' => $request->jenis_kelamin, 'wali_murid_id' => $request->wali_murid_id, - + // --- TAMBAHAN BARU: Simpan ke Database --- - 'latitude' => $request->latitude, - 'longitude' => $request->longitude, + 'latitude' => $request->latitude, + 'longitude' => $request->longitude, ]); return redirect()->route('siswa.index')->with('success', 'Data Siswa berhasil ditambahkan.'); @@ -67,31 +67,31 @@ public function update(Request $request, $id) $siswa = Siswa::findOrFail($id); $request->validate([ - 'nis' => 'required|unique:siswas,nis,'.$id, - 'nisn' => 'nullable|string', - 'nama_siswa' => 'required|string|max:255', - 'tempat_lahir' => 'required|string', + 'nis' => 'required|unique:siswas,nis,' . $id, + 'nisn' => 'nullable|string', + 'nama_siswa' => 'required|string|max:255', + 'tempat_lahir' => 'required|string', 'tanggal_lahir' => 'required|date', 'jenis_kelamin' => 'required|in:L,P', 'wali_murid_id' => 'required|exists:wali_murids,id', - + // --- TAMBAHAN BARU: Validasi Titik Koordinat Peta --- - 'latitude' => 'nullable|string', - 'longitude' => 'nullable|string', + 'latitude' => 'nullable|string', + 'longitude' => 'nullable|string', ]); $siswa->update([ - 'nis' => $request->nis, - 'nisn' => $request->nisn, - 'nama_siswa' => $request->nama_siswa, - 'tempat_lahir' => $request->tempat_lahir, + 'nis' => $request->nis, + 'nisn' => $request->nisn, + 'nama_siswa' => $request->nama_siswa, + 'tempat_lahir' => $request->tempat_lahir, 'tanggal_lahir' => $request->tanggal_lahir, 'jenis_kelamin' => $request->jenis_kelamin, 'wali_murid_id' => $request->wali_murid_id, - + // --- TAMBAHAN BARU: Update ke Database --- - 'latitude' => $request->latitude, - 'longitude' => $request->longitude, + 'latitude' => $request->latitude, + 'longitude' => $request->longitude, ]); return redirect()->route('siswa.index')->with('success', 'Data Siswa berhasil diperbarui!'); diff --git a/app/Http/Controllers/Admin/WaliMuridController.php b/app/Http/Controllers/Admin/WaliMuridController.php index ce79d18..c819b37 100644 --- a/app/Http/Controllers/Admin/WaliMuridController.php +++ b/app/Http/Controllers/Admin/WaliMuridController.php @@ -4,53 +4,54 @@ use App\Http\Controllers\Controller; use App\Models\WaliMurid; -use App\Models\User; +use App\Models\User; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Hash; -use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Facades\DB; class WaliMuridController extends Controller { public function index() { $walis = WaliMurid::with('user')->latest()->get(); - + // PERBAIKAN DI SINI: Sesuaikan dengan nama folder 'wali' - return view('admin.wali.index', compact('walis')); + return view('admin.wali.index', compact('walis')); } public function create() { - // PERBAIKAN DI SINI JUGA - return view('admin.wali.create'); + $zonas = \App\Models\MasterZona::orderBy('kategori', 'desc')->get()->groupBy('kategori'); + return view('admin.wali.create', compact('zonas')); } public function store(Request $request) { $request->validate([ 'nama_wali' => 'required', - 'email' => 'required|email|unique:users,email', - 'password' => 'required|min:6', - 'no_hp' => 'required', + 'email' => 'required|email|unique:users,email', + 'password' => 'required|min:6', + 'no_hp' => 'required', ]); DB::transaction(function () use ($request) { - + // 1. Buat User Login $user = User::create([ - 'name' => $request->nama_wali, - 'email' => $request->email, + 'name' => $request->nama_wali, + 'email' => $request->email, 'password' => Hash::make($request->password), - 'role' => 'wali_murid', + 'role' => 'wali_murid', ]); // 2. Buat Profil Wali WaliMurid::create([ - 'user_id' => $user->id, + 'user_id' => $user->id, 'nama_wali' => $request->nama_wali, - 'no_hp' => $request->no_hp, - 'alamat' => $request->alamat, - 'pekerjaan' => $request->pekerjaan, + 'no_hp' => $request->no_hp, + 'alamat' => $request->alamat, + 'pekerjaan' => $request->pekerjaan, + 'master_zona_id' => $request->master_zona_id, ]); }); @@ -60,7 +61,8 @@ public function store(Request $request) public function edit($id) { $data = WaliMurid::with('user')->findOrFail($id); - return view('admin.wali.edit', compact('data')); + $zonas = \App\Models\MasterZona::orderBy('kategori', 'desc')->get()->groupBy('kategori'); + return view('admin.wali.edit', compact('data', 'zonas')); } public function update(Request $request, $id) @@ -69,25 +71,33 @@ public function update(Request $request, $id) $request->validate([ 'nama_wali' => 'required', - 'email' => 'required|email|unique:users,email,' . $wali->user_id, - 'no_hp' => 'required', + 'email' => 'required|email|unique:users,email,' . $wali->user_id, + 'password' => 'nullable|min:6', + 'no_hp' => 'required', ]); DB::transaction(function () use ($request, $wali) { - + // 1. Update User Login if ($wali->user) { - $wali->user->update([ - 'name' => $request->nama_wali, - 'email' => $request->email, - ]); + $userData = [ + 'name' => $request->nama_wali, + 'email' => $request->email, + ]; + + if ($request->filled('password')) { + $userData['password'] = Hash::make($request->password); + } + + $wali->user->update($userData); } // 2. Update Profil Wali $wali->update([ 'nama_wali' => $request->nama_wali, - 'no_hp' => $request->no_hp, - 'alamat' => $request->alamat, + 'no_hp' => $request->no_hp, + 'alamat' => $request->alamat, + 'master_zona_id' => $request->master_zona_id, // 'pekerjaan' => $request->pekerjaan, // Form belum ada input pekerjaan ]); }); @@ -98,9 +108,9 @@ public function update(Request $request, $id) public function destroy($id) { $wali = WaliMurid::findOrFail($id); - - if($wali->user) { - $wali->user->delete(); + + if ($wali->user) { + $wali->user->delete(); } else { $wali->delete(); } diff --git a/app/Http/Controllers/Api/AuthController.php b/app/Http/Controllers/Api/AuthController.php index 18439b9..5c5401f 100644 --- a/app/Http/Controllers/Api/AuthController.php +++ b/app/Http/Controllers/Api/AuthController.php @@ -42,4 +42,25 @@ public function logout() Auth::logout(); return response()->json(['message' => 'Berhasil Logout']); } + + public function updateFcmToken(Request $request) + { + $request->validate([ + 'fcm_token' => 'required|string' + ]); + + $user = Auth::user(); + if ($user) { + $user->update(['fcm_token' => $request->fcm_token]); + return response()->json([ + 'success' => true, + 'message' => 'FCM Token updated successfully' + ], 200); + } + + return response()->json([ + 'success' => false, + 'message' => 'Unauthenticated' + ], 401); + } } \ No newline at end of file diff --git a/app/Http/Controllers/Api/GuruController.php b/app/Http/Controllers/Api/GuruController.php index 4be7ee6..e8b0dc2 100644 --- a/app/Http/Controllers/Api/GuruController.php +++ b/app/Http/Controllers/Api/GuruController.php @@ -212,9 +212,28 @@ public function scanJemput(Request $request) 'qr_code' => 'required', ]); + $qrCodeData = $request->qr_code; + $parts = explode('_', $qrCodeData); + $idSiswa = $parts[0]; + + if (count($parts) > 1) { + $qrDate = $parts[1]; + if ($qrDate !== date('Y-m-d')) { + return response()->json([ + 'success' => false, + 'message' => 'QR Code Kadaluarsa! Harap gunakan QR hari ini.' + ], 400); + } + } else { + return response()->json([ + 'success' => false, + 'message' => 'Format QR Code tidak valid atau Kadaluarsa!' + ], 400); + } + // Cari siswa berdasarkan qr_code (Biasanya NIS atau ID Siswa) - $siswa = Siswa::where('nis', $request->qr_code) - ->orWhere('id', $request->qr_code) + $siswa = Siswa::where('nis', $idSiswa) + ->orWhere('id', $idSiswa) ->first(); if (!$siswa) { @@ -224,18 +243,30 @@ public function scanJemput(Request $request) ], 404); } - // Catat Penjemputan - // Kita bisa atur default nama penjemput "Orang Tua/Wali" + // Cek request untuk nama penjemput dan status + $statusPenjemput = $request->status_penjemput ?? 'Orang Tua / Wali'; + Penjemputan::create([ 'siswa_id' => $siswa->id, - 'nama_penjemput' => 'Orang Tua / Wali', - 'status_hubungan' => 'Orang Tua', + 'nama_penjemput' => $statusPenjemput, + 'status_hubungan' => $statusPenjemput == 'Orang Tua' ? 'Orang Tua' : 'Diwakilkan', 'waktu_jemput' => now(), ]); + // --- TRIGGER FCM NOTIFICATION KE WALI MURID --- + if ($siswa->waliMurid && $siswa->waliMurid->user && $siswa->waliMurid->user->fcm_token) { + $token = $siswa->waliMurid->user->fcm_token; + $namaAnak = $siswa->nama_siswa ?? $siswa->nama_lengkap ?? 'Ananda'; + $this->sendFCMNotification( + "Penjemputan Berhasil", + "Ananda {$namaAnak} telah berhasil dijemput dan diverifikasi oleh Guru.", + [$token] + ); + } + return response()->json([ 'success' => true, - 'message' => 'Berhasil mencatat penjemputan untuk ' . $siswa->nama_lengkap + 'message' => 'Berhasil mencatat penjemputan untuk ' . ($siswa->nama_siswa ?? $siswa->nama_lengkap) ]); } } \ No newline at end of file diff --git a/app/Http/Controllers/Api/HomeVisitController.php b/app/Http/Controllers/Api/HomeVisitController.php new file mode 100644 index 0000000..a0f74f1 --- /dev/null +++ b/app/Http/Controllers/Api/HomeVisitController.php @@ -0,0 +1,45 @@ +get()->groupBy('kategori'); + + return response()->json([ + 'success' => true, + 'message' => 'Berhasil mengambil data zonasi', + 'data' => $zonas + ]); + } + + /** + * Endpoint 2: Mendapatkan daftar siswa berdasarkan zona_id + */ + public function getSiswaByZona($zona_id) + { + // Query Siswa yang berelasi dengan wali_murid, dimana wali_murid.master_zona_id = $zona_id + $siswas = Siswa::with('wali_murid') + ->whereHas('wali_murid', function ($query) use ($zona_id) { + $query->where('master_zona_id', $zona_id); + }) + ->get(); + + return response()->json([ + 'success' => true, + 'message' => 'Berhasil mengambil data siswa di zona tersebut', + 'data' => $siswas + ]); + } +} diff --git a/app/Http/Controllers/Api/WaliController.php b/app/Http/Controllers/Api/WaliController.php index 328f1a3..211ae52 100644 --- a/app/Http/Controllers/Api/WaliController.php +++ b/app/Http/Controllers/Api/WaliController.php @@ -40,8 +40,14 @@ public function getDashboard(Request $request) // 3. Pengumuman Aktif Terbaru $pengumuman = Pengumuman::where('status', true) - ->where('tanggal_mulai', '<=', now()) - ->where('tanggal_selesai', '>=', now()) + ->where(function ($query) { + $query->whereNull('tanggal_mulai') + ->orWhereDate('tanggal_mulai', '<=', now()); + }) + ->where(function ($query) { + $query->whereNull('tanggal_selesai') + ->orWhereDate('tanggal_selesai', '>=', now()); + }) ->latest() ->first(); @@ -76,9 +82,21 @@ public function getDashboard(Request $request) // Murni kalkulasi berdasarkan data riil, 0 jika kosong $percentage = $count > 0 ? round($totalScore / $count) : 0; + $predikat = "Perlu Bimbingan"; + if ($percentage >= 76) $predikat = "Sangat Baik"; + elseif ($percentage >= 51) $predikat = "Baik"; + elseif ($percentage >= 26) $predikat = "Cukup"; + + $narasi = null; + if ($count > 0) { + $namaAnak = $siswa->nama_siswa ?? $siswa->nama_lengkap ?? 'Ananda'; + $narasi = "Ananda {$namaAnak} telah menunjukkan perkembangan yang {$predikat} pada aspek {$aspek} dengan capaian {$percentage}%."; + } + $progressPerkembangan[] = [ 'aspek' => $aspek, - 'nilai' => $percentage + 'nilai' => $percentage, + 'narasi' => $narasi ]; } diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 8677cd5..09f770a 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -2,7 +2,62 @@ namespace App\Http\Controllers; +use Kreait\Firebase\Factory; +use Kreait\Firebase\Messaging\CloudMessage; +use Kreait\Firebase\Messaging\Notification; +use Kreait\Firebase\Messaging\AndroidConfig; + abstract class Controller { - // + public function sendFCMNotification($title, $body, $tokens) + { + $credentialsFilePath = storage_path('firebase-auth.json'); + + if (!file_exists($credentialsFilePath)) { + \Log::error("FCM Service Account file not found at: " . $credentialsFilePath); + return false; + } + + try { + $factory = (new Factory)->withServiceAccount($credentialsFilePath); + $messaging = $factory->createMessaging(); + + $responses = []; + + foreach ($tokens as $fcmToken) { + $message = CloudMessage::withTarget('token', $fcmToken) + ->withNotification(Notification::create($title, $body)) + ->withAndroidConfig(AndroidConfig::fromArray([ + 'priority' => 'high', + 'notification' => [ + 'channel_id' => 'paud_notif_channel', + 'sound' => 'default' + ] + ])); + + try { + $result = $messaging->send($message); + $responses[] = $result; + \Log::info("FCM Response for token {$fcmToken}: Sukses via Kreait. Result: " . json_encode($result)); + } catch (\Kreait\Firebase\Exception\MessagingException $e) { + \Log::error("Kreait FCM Error for token {$fcmToken}: " . $e->getMessage()); + // ERROR HANDLING TEGAS SEPERTI SEBELUMNYA + dd([ + 'STATUS' => 'ERROR_DITOLAK_GOOGLE', + 'FCM_ERROR' => $e->getMessage(), + 'FCM_ERROR_DETAILS' => $e->errors() + ]); + } + } + + return $responses; + } catch (\Exception $e) { + \Log::error("FCM System Error: " . $e->getMessage()); + dd([ + 'STATUS' => 'FATAL_SYSTEM_ERROR', + 'ERROR' => $e->getMessage() + ]); + return false; + } + } } diff --git a/app/Models/MasterZona.php b/app/Models/MasterZona.php new file mode 100644 index 0000000..ed8e3b1 --- /dev/null +++ b/app/Models/MasterZona.php @@ -0,0 +1,11 @@ +hasMany(Siswa::class, 'wali_id'); } + + public function zona() + { + return $this->belongsTo(MasterZona::class, 'master_zona_id'); + } } \ No newline at end of file diff --git a/composer.json b/composer.json index 19c7a43..06be95a 100644 --- a/composer.json +++ b/composer.json @@ -8,6 +8,8 @@ "require": { "php": "^8.2", "doctrine/dbal": "^4.4", + "google/apiclient": "^2.19", + "kreait/firebase-php": "^7.24", "laravel/framework": "^12.0", "laravel/sanctum": "^4.0", "laravel/tinker": "^2.10.1", diff --git a/composer.lock b/composer.lock index 89966c6..83d7dd5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,210 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "2a5bf23f8b08ec6fff703c477ba59a68", + "content-hash": "0ac1a88ea5db56345ebe78eccb50a1fd", "packages": [ + { + "name": "beste/clock", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/beste/clock.git", + "reference": "7004b55fcd54737b539886244b3a3b2188181974" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/beste/clock/zipball/7004b55fcd54737b539886244b3a3b2188181974", + "reference": "7004b55fcd54737b539886244b3a3b2188181974", + "shasum": "" + }, + "require": { + "php": "^8.0", + "psr/clock": "^1.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9.1", + "phpstan/phpstan-phpunit": "^1.2.2", + "phpstan/phpstan-strict-rules": "^1.4.4", + "phpunit/phpunit": "^9.5.26", + "psalm/plugin-phpunit": "^0.16.1", + "vimeo/psalm": "^4.29" + }, + "type": "library", + "autoload": { + "files": [ + "src/Clock.php" + ], + "psr-4": { + "Beste\\Clock\\": "src/Clock" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérôme Gamez", + "email": "jerome@gamez.name" + } + ], + "description": "A collection of Clock implementations", + "keywords": [ + "clock", + "clock-interface", + "psr-20", + "psr20" + ], + "support": { + "issues": "https://github.com/beste/clock/issues", + "source": "https://github.com/beste/clock/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/jeromegamez", + "type": "github" + } + ], + "time": "2022-11-26T18:03:05+00:00" + }, + { + "name": "beste/in-memory-cache", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/beste/in-memory-cache-php.git", + "reference": "1b9fbfcfbd0b657b90a759ac41b22748501c7f0e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/beste/in-memory-cache-php/zipball/1b9fbfcfbd0b657b90a759ac41b22748501c7f0e", + "reference": "1b9fbfcfbd0b657b90a759ac41b22748501c7f0e", + "shasum": "" + }, + "require": { + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "psr/cache": "^2.0 || ^3.0", + "psr/clock": "^1.0" + }, + "provide": { + "psr/cache-implementation": "2.0 || 3.0" + }, + "require-dev": { + "beste/clock": "^3.0", + "beste/php-cs-fixer-config": "^3.2.0", + "friendsofphp/php-cs-fixer": "^3.62.0", + "phpstan/extension-installer": "^1.4.1", + "phpstan/phpstan": "^2.0.1", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^10.5.2 || ^11.3.1", + "symfony/var-dumper": "^6.4 || ^7.1.3" + }, + "suggest": { + "psr/clock-implementation": "Allows injecting a Clock, for example a frozen clock for testing" + }, + "type": "library", + "autoload": { + "psr-4": { + "Beste\\Cache\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérôme Gamez", + "email": "jerome@gamez.name" + } + ], + "description": "A PSR-6 In-Memory cache that can be used as a fallback implementation and/or in tests.", + "keywords": [ + "beste", + "cache", + "psr-6" + ], + "support": { + "issues": "https://github.com/beste/in-memory-cache-php/issues", + "source": "https://github.com/beste/in-memory-cache-php/tree/1.4.0" + }, + "funding": [ + { + "url": "https://github.com/jeromegamez", + "type": "github" + } + ], + "time": "2025-09-29T22:05:17+00:00" + }, + { + "name": "beste/json", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/beste/json.git", + "reference": "976525f1ce2323a4e044364269d60b402603e216" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/beste/json/zipball/976525f1ce2323a4e044364269d60b402603e216", + "reference": "976525f1ce2323a4e044364269d60b402603e216", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan": "^2.0.4", + "phpstan/phpstan-phpunit": "^2.0.2", + "phpstan/phpstan-strict-rules": "^2.0.1", + "phpunit/phpunit": "^10.4.2", + "rector/rector": "^2.0.3" + }, + "type": "library", + "autoload": { + "files": [ + "src/Json.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérôme Gamez", + "email": "jerome@gamez.name" + } + ], + "description": "A simple JSON helper to decode and encode JSON", + "keywords": [ + "helper", + "json" + ], + "support": { + "issues": "https://github.com/beste/json/issues", + "source": "https://github.com/beste/json/tree/1.7.0" + }, + "funding": [ + { + "url": "https://github.com/jeromegamez", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/beste/json", + "type": "tidelift" + } + ], + "time": "2025-09-11T23:36:19+00:00" + }, { "name": "brick/math", "version": "0.14.0", @@ -135,6 +337,83 @@ ], "time": "2024-02-09T16:56:22+00:00" }, + { + "name": "cuyz/valinor", + "version": "2.4.0", + "source": { + "type": "git", + "url": "https://github.com/CuyZ/Valinor.git", + "reference": "3b0afa3a287ed7f3a69aab223726cf1139454c34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CuyZ/Valinor/zipball/3b0afa3a287ed7f3a69aab223726cf1139454c34", + "reference": "3b0afa3a287ed7f3a69aab223726cf1139454c34", + "shasum": "" + }, + "require": { + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0" + }, + "conflict": { + "phpstan/phpstan": "<1.0 || >= 3.0", + "vimeo/psalm": "<5.0 || >=7.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.91", + "infection/infection": "^0.32", + "marcocesarato/php-conventional-changelog": "^1.12", + "mikey179/vfsstream": "^1.6.10", + "phpbench/phpbench": "^1.3", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^11.5", + "psr/http-message": "^2.0", + "rector/rector": "^2.0", + "vimeo/psalm": "^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "CuyZ\\Valinor\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Romain Canon", + "email": "romain.hydrocanon@gmail.com", + "homepage": "https://github.com/romm" + } + ], + "description": "Dependency free PHP library that helps to map any input into a strongly-typed structure.", + "homepage": "https://github.com/CuyZ/Valinor", + "keywords": [ + "array", + "conversion", + "hydrator", + "json", + "mapper", + "mapping", + "object", + "tree", + "yaml" + ], + "support": { + "issues": "https://github.com/CuyZ/Valinor/issues", + "source": "https://github.com/CuyZ/Valinor/tree/2.4.0" + }, + "funding": [ + { + "url": "https://github.com/romm", + "type": "github" + } + ], + "time": "2026-03-23T17:38:05+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.3", @@ -663,6 +942,126 @@ ], "time": "2025-03-06T22:45:56+00:00" }, + { + "name": "fig/http-message-util", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-message-util/issues", + "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" + }, + "time": "2020-11-24T22:02:12+00:00" + }, + { + "name": "firebase/php-jwt", + "version": "v7.0.5", + "source": { + "type": "git", + "url": "https://github.com/googleapis/php-jwt.git", + "reference": "47ad26bab5e7c70ae8a6f08ed25ff83631121380" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/php-jwt/zipball/47ad26bab5e7c70ae8a6f08ed25ff83631121380", + "reference": "47ad26bab5e7c70ae8a6f08ed25ff83631121380", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.4", + "phpfastcache/phpfastcache": "^9.2", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^2.0||^3.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/googleapis/php-jwt/issues", + "source": "https://github.com/googleapis/php-jwt/tree/v7.0.5" + }, + "time": "2026-04-01T20:38:03+00:00" + }, { "name": "fruitcake/php-cors", "version": "v1.3.0", @@ -734,6 +1133,557 @@ ], "time": "2023-10-12T05:21:21+00:00" }, + { + "name": "google/apiclient", + "version": "v2.19.3", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client.git", + "reference": "a1f02761994fd9defb20f6f1449205fd66f450de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/a1f02761994fd9defb20f6f1449205fd66f450de", + "reference": "a1f02761994fd9defb20f6f1449205fd66f450de", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "^6.0||^7.0", + "google/apiclient-services": "~0.350", + "google/auth": "^1.37", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.6", + "monolog/monolog": "^2.9||^3.0", + "php": "^8.1" + }, + "require-dev": { + "cache/filesystem-adapter": "^1.1", + "composer/composer": "^2.9", + "phpcompatibility/php-compatibility": "^9.2", + "phpspec/prophecy-phpunit": "^2.1", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.8", + "symfony/css-selector": "~2.1", + "symfony/dom-crawler": "~2.1" + }, + "suggest": { + "cache/filesystem-adapter": "For caching certs and tokens (using Google\\Client::setCache)" + }, + "type": "library", + "extra": { + "component": { + "entry": "src/Client.php" + }, + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/aliases.php" + ], + "psr-4": { + "Google\\": "src/" + }, + "classmap": [ + "src/aliases.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/google-api-php-client/issues", + "source": "https://github.com/googleapis/google-api-php-client/tree/v2.19.3" + }, + "time": "2026-05-04T21:00:36+00:00" + }, + { + "name": "google/apiclient-services", + "version": "v0.440.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-api-php-client-services.git", + "reference": "f835f7a84611071ca2f58e8f44aac497d3aa7c44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/f835f7a84611071ca2f58e8f44aac497d3aa7c44", + "reference": "f835f7a84611071ca2f58e8f44aac497d3aa7c44", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6" + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ], + "psr-4": { + "Google\\Service\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Client library for Google APIs", + "homepage": "http://developers.google.com/api-client-library/php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/google-api-php-client-services/issues", + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.440.0" + }, + "time": "2026-05-04T01:36:24+00:00" + }, + { + "name": "google/auth", + "version": "v1.50.1", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-auth-library-php.git", + "reference": "870c17ee3a1d73338d39a9ffa77a700ba77f5a83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/870c17ee3a1d73338d39a9ffa77a700ba77f5a83", + "reference": "870c17ee3a1d73338d39a9ffa77a700ba77f5a83", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "^6.0||^7.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.4.5", + "php": "^8.1", + "psr/cache": "^2.0||^3.0", + "psr/http-message": "^1.1||^2.0", + "psr/log": "^2.0||^3.0" + }, + "require-dev": { + "guzzlehttp/promises": "^2.0", + "kelvinmo/simplejwt": "^1.1.0", + "phpseclib/phpseclib": "^3.0.35", + "phpspec/prophecy-phpunit": "^2.1", + "phpunit/phpunit": "^9.6", + "sebastian/comparator": ">=1.2.3", + "squizlabs/php_codesniffer": "^4.0", + "symfony/filesystem": "^6.3||^7.3", + "symfony/process": "^6.0||^7.0", + "webmozart/assert": "^1.11||^2.0" + }, + "suggest": { + "phpseclib/phpseclib": "May be used in place of OpenSSL for signing strings or for token management. Please require version ^2." + }, + "type": "library", + "autoload": { + "psr-4": { + "Google\\Auth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google Auth Library for PHP", + "homepage": "https://github.com/google/google-auth-library-php", + "keywords": [ + "Authentication", + "google", + "oauth2" + ], + "support": { + "docs": "https://cloud.google.com/php/docs/reference/auth/latest", + "issues": "https://github.com/googleapis/google-auth-library-php/issues", + "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.50.1" + }, + "time": "2026-03-18T20:03:29+00:00" + }, + { + "name": "google/cloud-core", + "version": "v1.72.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-cloud-php-core.git", + "reference": "62cf5d2243af167c75019743c5aebcf25c3905ca" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-cloud-php-core/zipball/62cf5d2243af167c75019743c5aebcf25c3905ca", + "reference": "62cf5d2243af167c75019743c5aebcf25c3905ca", + "shasum": "" + }, + "require": { + "google/auth": "^1.34", + "google/gax": "^1.38.0", + "guzzlehttp/guzzle": "^6.5.8||^7.4.4", + "guzzlehttp/promises": "^1.4||^2.0", + "guzzlehttp/psr7": "^2.6", + "monolog/monolog": "^2.9||^3.0", + "php": "^8.1", + "psr/http-message": "^1.0||^2.0", + "rize/uri-template": "~0.3||~0.4" + }, + "require-dev": { + "erusev/parsedown": "^1.6", + "google/cloud-common-protos": "~0.5||^1.0", + "nikic/php-parser": "^5.6", + "opis/closure": "^3.7|^4.0", + "phpdocumentor/reflection": "^6.0", + "phpdocumentor/reflection-docblock": "^5.3.3||^6.0", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.0", + "squizlabs/php_codesniffer": "2.*" + }, + "suggest": { + "opis/closure": "May be used to serialize closures to process jobs in the batch daemon. Please require version ^3.", + "symfony/lock": "Required for the Spanner cached based session pool. Please require the following commit: 3.3.x-dev#1ba6ac9" + }, + "bin": [ + "bin/google-cloud-batch" + ], + "type": "library", + "extra": { + "component": { + "id": "cloud-core", + "path": "Core", + "entry": "src/ServiceBuilder.php", + "target": "googleapis/google-cloud-php-core.git" + } + }, + "autoload": { + "psr-4": { + "Google\\Cloud\\Core\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google Cloud PHP shared dependency, providing functionality useful to all components.", + "support": { + "source": "https://github.com/googleapis/google-cloud-php-core/tree/v1.72.0" + }, + "time": "2026-04-09T21:01:46+00:00" + }, + { + "name": "google/cloud-storage", + "version": "v1.51.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-cloud-php-storage.git", + "reference": "9ba3d5e8cbd53bf67fab644b5be310e719533def" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-cloud-php-storage/zipball/9ba3d5e8cbd53bf67fab644b5be310e719533def", + "reference": "9ba3d5e8cbd53bf67fab644b5be310e719533def", + "shasum": "" + }, + "require": { + "google/cloud-core": "^1.72.0", + "php": "^8.1", + "ramsey/uuid": "^4.2.3" + }, + "require-dev": { + "erusev/parsedown": "^1.6", + "google/cloud-pubsub": "^2.0", + "nikic/php-parser": "^5", + "phpdocumentor/reflection": "^6.0", + "phpdocumentor/reflection-docblock": "^5.3.3", + "phpseclib/phpseclib": "^2.0||^3.0", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.0", + "squizlabs/php_codesniffer": "2.*" + }, + "suggest": { + "google/cloud-pubsub": "May be used to register a topic to receive bucket notifications.", + "phpseclib/phpseclib": "May be used in place of OpenSSL for creating signed Cloud Storage URLs. Please require version ^2." + }, + "type": "library", + "extra": { + "component": { + "id": "cloud-storage", + "path": "Storage", + "entry": "src/StorageClient.php", + "target": "googleapis/google-cloud-php-storage.git" + } + }, + "autoload": { + "psr-4": { + "Google\\Cloud\\Storage\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Cloud Storage Client for PHP", + "support": { + "source": "https://github.com/googleapis/google-cloud-php-storage/tree/v1.51.0" + }, + "time": "2026-04-09T21:01:46+00:00" + }, + { + "name": "google/common-protos", + "version": "4.14.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/common-protos-php.git", + "reference": "f8e72f7b581702e7c3ee0776144f4974da172428" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/common-protos-php/zipball/f8e72f7b581702e7c3ee0776144f4974da172428", + "reference": "f8e72f7b581702e7c3ee0776144f4974da172428", + "shasum": "" + }, + "require": { + "google/protobuf": "^4.31||^5.0", + "php": "^8.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6" + }, + "type": "library", + "extra": { + "component": { + "id": "common-protos", + "path": "CommonProtos", + "entry": "README.md", + "target": "googleapis/common-protos-php.git" + } + }, + "autoload": { + "psr-4": { + "Google\\Api\\": "src/Api", + "Google\\Iam\\": "src/Iam", + "Google\\Rpc\\": "src/Rpc", + "Google\\Type\\": "src/Type", + "Google\\Cloud\\": "src/Cloud", + "GPBMetadata\\Google\\Api\\": "metadata/Api", + "GPBMetadata\\Google\\Iam\\": "metadata/Iam", + "GPBMetadata\\Google\\Rpc\\": "metadata/Rpc", + "GPBMetadata\\Google\\Type\\": "metadata/Type", + "GPBMetadata\\Google\\Cloud\\": "metadata/Cloud", + "GPBMetadata\\Google\\Logging\\": "metadata/Logging" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google API Common Protos for PHP", + "homepage": "https://github.com/googleapis/common-protos-php", + "keywords": [ + "google" + ], + "support": { + "source": "https://github.com/googleapis/common-protos-php/tree/v4.14.0" + }, + "time": "2026-04-09T21:01:46+00:00" + }, + { + "name": "google/gax", + "version": "v1.42.3", + "source": { + "type": "git", + "url": "https://github.com/googleapis/gax-php.git", + "reference": "9dce5145169f2390ef2500d638c3cb5632054a96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/gax-php/zipball/9dce5145169f2390ef2500d638c3cb5632054a96", + "reference": "9dce5145169f2390ef2500d638c3cb5632054a96", + "shasum": "" + }, + "require": { + "google/auth": "^1.49", + "google/common-protos": "^4.4", + "google/grpc-gcp": "^0.4", + "google/longrunning": "~0.4", + "google/protobuf": "^4.31||^5.34", + "grpc/grpc": "^1.13", + "guzzlehttp/promises": "^2.0", + "guzzlehttp/psr7": "^2.0", + "php": "^8.1", + "ramsey/uuid": "^4.0" + }, + "conflict": { + "ext-protobuf": "<4.31.0" + }, + "require-dev": { + "google/cloud-tools": "^0.16.1", + "phpspec/prophecy-phpunit": "^2.1", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Google\\ApiCore\\": "src", + "GPBMetadata\\ApiCore\\": "metadata/ApiCore" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Google API Core for PHP", + "homepage": "https://github.com/googleapis/gax-php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/gax-php/issues", + "source": "https://github.com/googleapis/gax-php/tree/v1.42.3" + }, + "time": "2026-04-30T20:59:42+00:00" + }, + { + "name": "google/grpc-gcp", + "version": "0.4.2", + "source": { + "type": "git", + "url": "https://github.com/GoogleCloudPlatform/grpc-gcp-php.git", + "reference": "1049c0c15b6a1789fdeb52af688a94d540932469" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GoogleCloudPlatform/grpc-gcp-php/zipball/1049c0c15b6a1789fdeb52af688a94d540932469", + "reference": "1049c0c15b6a1789fdeb52af688a94d540932469", + "shasum": "" + }, + "require": { + "google/auth": "^1.3", + "google/protobuf": "^v3.25.3||^4.26.1||^5.0", + "grpc/grpc": "^v1.13.0", + "php": "^8.0", + "psr/cache": "^1.0.1||^2.0.0||^3.0.0" + }, + "require-dev": { + "google/cloud-spanner": "^1.7", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Grpc\\Gcp\\": "src/" + }, + "classmap": [ + "src/generated/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "gRPC GCP library for channel management", + "support": { + "issues": "https://github.com/GoogleCloudPlatform/grpc-gcp-php/issues", + "source": "https://github.com/GoogleCloudPlatform/grpc-gcp-php/tree/v0.4.2" + }, + "time": "2026-03-12T22:56:09+00:00" + }, + { + "name": "google/longrunning", + "version": "0.7.1", + "source": { + "type": "git", + "url": "https://github.com/googleapis/php-longrunning.git", + "reference": "cac9bedf199239ae2b1acd4a8e4ea2276bd9f55a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/php-longrunning/zipball/cac9bedf199239ae2b1acd4a8e4ea2276bd9f55a", + "reference": "cac9bedf199239ae2b1acd4a8e4ea2276bd9f55a", + "shasum": "" + }, + "require-dev": { + "google/gax": "^1.38.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "component": { + "id": "longrunning", + "path": "LongRunning", + "entry": null, + "target": "googleapis/php-longrunning" + } + }, + "autoload": { + "psr-4": { + "Google\\LongRunning\\": "src/LongRunning", + "Google\\ApiCore\\LongRunning\\": "src/ApiCore/LongRunning", + "GPBMetadata\\Google\\Longrunning\\": "metadata/Longrunning" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google LongRunning Client for PHP", + "support": { + "source": "https://github.com/googleapis/php-longrunning/tree/v0.7.1" + }, + "time": "2026-03-31T19:52:22+00:00" + }, + { + "name": "google/protobuf", + "version": "v5.34.1", + "source": { + "type": "git", + "url": "https://github.com/protocolbuffers/protobuf-php.git", + "reference": "da52fbc6bb574bfa6693ee2c86f9096f7b7f003b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/da52fbc6bb574bfa6693ee2c86f9096f7b7f003b", + "reference": "da52fbc6bb574bfa6693ee2c86f9096f7b7f003b", + "shasum": "" + }, + "require": { + "php": ">=8.2.0" + }, + "require-dev": { + "phpunit/phpunit": ">=11.5.0 <12.0.0" + }, + "suggest": { + "ext-bcmath": "Need to support JSON deserialization" + }, + "type": "library", + "autoload": { + "psr-4": { + "Google\\Protobuf\\": "src/Google/Protobuf", + "GPBMetadata\\Google\\Protobuf\\": "src/GPBMetadata/Google/Protobuf" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "proto library for PHP", + "homepage": "https://developers.google.com/protocol-buffers/", + "keywords": [ + "proto" + ], + "support": { + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v5.34.1" + }, + "time": "2026-03-19T20:51:56+00:00" + }, { "name": "graham-campbell/result-type", "version": "v1.1.3", @@ -796,6 +1746,50 @@ ], "time": "2024-07-20T21:45:45+00:00" }, + { + "name": "grpc/grpc", + "version": "1.80.0", + "source": { + "type": "git", + "url": "https://github.com/grpc/grpc-php.git", + "reference": "a0dc463d5d5064cdd7ff344f13f61d7e233f9b5a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/grpc/grpc-php/zipball/a0dc463d5d5064cdd7ff344f13f61d7e233f9b5a", + "reference": "a0dc463d5d5064cdd7ff344f13f61d7e233f9b5a", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "google/auth": "^v1.3.0" + }, + "suggest": { + "ext-protobuf": "For better performance, install the protobuf C extension.", + "google/protobuf": "To get started using grpc quickly, install the native protobuf library." + }, + "type": "library", + "autoload": { + "psr-4": { + "Grpc\\": "src/lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "gRPC library for PHP", + "homepage": "https://grpc.io", + "keywords": [ + "rpc" + ], + "support": { + "source": "https://github.com/grpc/grpc-php/tree/v1.80.0" + }, + "time": "2026-03-30T09:22:39+00:00" + }, { "name": "guzzlehttp/guzzle", "version": "7.10.0", @@ -1207,6 +2201,181 @@ ], "time": "2025-08-22T14:27:06+00:00" }, + { + "name": "kreait/firebase-php", + "version": "7.24.1", + "source": { + "type": "git", + "url": "https://github.com/beste/firebase-php.git", + "reference": "935292e2af33af0120654ce704f1dc8f1c03025b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/beste/firebase-php/zipball/935292e2af33af0120654ce704f1dc8f1c03025b", + "reference": "935292e2af33af0120654ce704f1dc8f1c03025b", + "shasum": "" + }, + "require": { + "beste/clock": "^3.0", + "beste/in-memory-cache": "^1.3.1", + "beste/json": "^1.5.1", + "cuyz/valinor": "^2.2.1", + "ext-ctype": "*", + "ext-filter": "*", + "ext-json": "*", + "ext-mbstring": "*", + "fig/http-message-util": "^1.1.5", + "firebase/php-jwt": "^6.10.2 || ^7.0.2", + "google/auth": "^1.45", + "google/cloud-storage": "^1.48.7", + "guzzlehttp/guzzle": "^7.9.2", + "guzzlehttp/promises": "^2.0.4", + "guzzlehttp/psr7": "^2.7", + "kreait/firebase-tokens": "^5.2", + "lcobucci/jwt": "^5.3", + "mtdowling/jmespath.php": "^2.8.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "psr/cache": "^2.0 || ^3.0", + "psr/clock": "^1.0", + "psr/http-client": "^1.0.3", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0", + "psr/log": "^3.0.2" + }, + "require-dev": { + "google/cloud-firestore": "^1.54.2", + "php-cs-fixer/shim": "^3.88.2", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.31", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.7", + "phpstan/phpstan-strict-rules": "^2.0.7", + "phpunit/phpunit": "^10.5.58", + "rector/rector": "^2.2.2", + "shipmonk/composer-dependency-analyser": "^1.8.3", + "symfony/var-dumper": "^6.4.15 || ^7.3.4", + "vlucas/phpdotenv": "^5.6.2" + }, + "suggest": { + "google/cloud-firestore": "^1.0 to use the Firestore component" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-7.x": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Kreait\\Firebase\\": "src/Firebase" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérôme Gamez", + "homepage": "https://github.com/jeromegamez" + } + ], + "description": "Firebase Admin SDK", + "homepage": "https://github.com/kreait/firebase-php", + "keywords": [ + "api", + "database", + "firebase", + "google", + "sdk" + ], + "support": { + "docs": "https://firebase-php.readthedocs.io", + "issues": "https://github.com/kreait/firebase-php/issues", + "source": "https://github.com/kreait/firebase-php" + }, + "funding": [ + { + "url": "https://github.com/sponsors/jeromegamez", + "type": "github" + } + ], + "time": "2026-02-18T23:43:18+00:00" + }, + { + "name": "kreait/firebase-tokens", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/beste/firebase-tokens-php.git", + "reference": "5dc119c8c29fcab1fb3a35ed5164dee0d33e4430" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/beste/firebase-tokens-php/zipball/5dc119c8c29fcab1fb3a35ed5164dee0d33e4430", + "reference": "5dc119c8c29fcab1fb3a35ed5164dee0d33e4430", + "shasum": "" + }, + "require": { + "beste/clock": "^3.0", + "ext-json": "*", + "ext-openssl": "*", + "fig/http-message-util": "^1.1.5", + "guzzlehttp/guzzle": "^7.8", + "lcobucci/jwt": "^5.2", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.62.0", + "phpstan/extension-installer": "^1.4.1", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5.30", + "rector/rector": "^2.1", + "symfony/cache": "^6.4.3 || ^7.1.3", + "symfony/var-dumper": "^6.4.3 || ^7.1.3" + }, + "suggest": { + "psr/cache-implementation": "to cache fetched remote public keys" + }, + "type": "library", + "autoload": { + "psr-4": { + "Kreait\\Firebase\\JWT\\": "src/JWT" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérôme Gamez", + "homepage": "https://github.com/jeromegamez" + } + ], + "description": "A library to work with Firebase tokens", + "homepage": "https://github.com/kreait/firebase-token-php", + "keywords": [ + "Authentication", + "auth", + "firebase", + "google", + "token" + ], + "support": { + "issues": "https://github.com/beste/firebase-tokens-php/issues", + "source": "https://github.com/beste/firebase-tokens-php/tree/5.3.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/jeromegamez", + "type": "github" + } + ], + "time": "2025-09-11T23:24:49+00:00" + }, { "name": "laravel/framework", "version": "v12.29.0", @@ -1677,6 +2846,79 @@ }, "time": "2025-01-27T14:24:01+00:00" }, + { + "name": "lcobucci/jwt", + "version": "5.6.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "bb3e9f21e4196e8afc41def81ef649c164bca25e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/bb3e9f21e4196e8afc41def81ef649c164bca25e", + "reference": "bb3e9f21e4196e8afc41def81ef649c164bca25e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-sodium": "*", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "psr/clock": "^1.0" + }, + "require-dev": { + "infection/infection": "^0.29", + "lcobucci/clock": "^3.2", + "lcobucci/coding-standard": "^11.0", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.10.7", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.10", + "phpstan/phpstan-strict-rules": "^1.5.0", + "phpunit/phpunit": "^11.1" + }, + "suggest": { + "lcobucci/clock": ">= 3.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/5.6.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2025-10-17T11:30:53+00:00" + }, { "name": "league/commonmark", "version": "2.7.1", @@ -2407,6 +3649,72 @@ ], "time": "2025-03-24T10:02:05+00:00" }, + { + "name": "mtdowling/jmespath.php", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0" + }, + "time": "2024-09-04T18:46:31+00:00" + }, { "name": "nesbot/carbon", "version": "3.10.3", @@ -3691,6 +4999,70 @@ }, "time": "2025-09-04T20:59:21+00:00" }, + { + "name": "rize/uri-template", + "version": "0.4.1", + "source": { + "type": "git", + "url": "https://github.com/rize/UriTemplate.git", + "reference": "abb53c8b73a5b6c24e11f49036ab842f560cad33" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rize/UriTemplate/zipball/abb53c8b73a5b6c24e11f49036ab842f560cad33", + "reference": "abb53c8b73a5b6c24e11f49036ab842f560cad33", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.63", + "phpstan/phpstan": "^1.12", + "phpunit/phpunit": "~10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Rize\\": "src/Rize" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marut K", + "homepage": "http://twitter.com/rezigned" + } + ], + "description": "PHP URI Template (RFC 6570) supports both expansion & extraction", + "keywords": [ + "RFC 6570", + "template", + "uri" + ], + "support": { + "issues": "https://github.com/rize/UriTemplate/issues", + "source": "https://github.com/rize/UriTemplate/tree/0.4.1" + }, + "funding": [ + { + "url": "https://www.paypal.me/rezigned", + "type": "custom" + }, + { + "url": "https://github.com/rezigned", + "type": "github" + }, + { + "url": "https://opencollective.com/rize-uri-template", + "type": "open_collective" + } + ], + "time": "2025-12-02T15:19:04+00:00" + }, { "name": "symfony/clock", "version": "v7.3.0", diff --git a/database/migrations/2026_05_06_140515_add_fcm_token_to_users_table.php b/database/migrations/2026_05_06_140515_add_fcm_token_to_users_table.php new file mode 100644 index 0000000..484c4a5 --- /dev/null +++ b/database/migrations/2026_05_06_140515_add_fcm_token_to_users_table.php @@ -0,0 +1,28 @@ +text('fcm_token')->nullable()->after('remember_token'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('fcm_token'); + }); + } +}; diff --git a/database/migrations/2026_05_09_034457_create_master_zonas_table.php b/database/migrations/2026_05_09_034457_create_master_zonas_table.php new file mode 100644 index 0000000..c44984d --- /dev/null +++ b/database/migrations/2026_05_09_034457_create_master_zonas_table.php @@ -0,0 +1,28 @@ +id(); + $table->string('nama_zona'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('master_zonas'); + } +}; diff --git a/database/migrations/2026_05_09_034506_add_master_zona_id_to_wali_murids_table.php b/database/migrations/2026_05_09_034506_add_master_zona_id_to_wali_murids_table.php new file mode 100644 index 0000000..8afe437 --- /dev/null +++ b/database/migrations/2026_05_09_034506_add_master_zona_id_to_wali_murids_table.php @@ -0,0 +1,29 @@ +foreignId('master_zona_id')->nullable()->constrained('master_zonas')->nullOnDelete(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('wali_murids', function (Blueprint $table) { + $table->dropForeign(['master_zona_id']); + $table->dropColumn('master_zona_id'); + }); + } +}; diff --git a/database/migrations/2026_05_09_042935_add_kategori_to_master_zonas_table.php b/database/migrations/2026_05_09_042935_add_kategori_to_master_zonas_table.php new file mode 100644 index 0000000..c4843a0 --- /dev/null +++ b/database/migrations/2026_05_09_042935_add_kategori_to_master_zonas_table.php @@ -0,0 +1,28 @@ +string('kategori')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('master_zonas', function (Blueprint $table) { + $table->dropColumn('kategori'); + }); + } +}; diff --git a/database/seeders/MasterZonaSeeder.php b/database/seeders/MasterZonaSeeder.php new file mode 100644 index 0000000..603c482 --- /dev/null +++ b/database/seeders/MasterZonaSeeder.php @@ -0,0 +1,35 @@ + $zona, 'kategori' => 'Kota Madiun']); + } + + foreach ($kabupatenMadiun as $zona) { + \App\Models\MasterZona::create(['nama_zona' => $zona, 'kategori' => 'Kabupaten Madiun']); + } + } +} diff --git a/resources/views.zip b/resources/views.zip new file mode 100644 index 0000000..ecfc9ba Binary files /dev/null and b/resources/views.zip differ diff --git a/resources/views/admin/akun/index.blade.php b/resources/views/admin/akun/index.blade.php index 67c48ae..34191ee 100644 --- a/resources/views/admin/akun/index.blade.php +++ b/resources/views/admin/akun/index.blade.php @@ -1,102 +1,103 @@ @extends('layouts.app') @section('content') -
-
-

🔐 Daftar Akun

- + Tambah Akun +
+
+

🔐 Daftar Akun

+ + + Tambah Akun +
+ + @if(session('success')) +
{{ session('success') }}
+ @endif + @if(session('error')) +
{{ session('error') }}
+ @endif + + + + + + + + + + + + + + @forelse ($users as $i => $user) + + + + + + + {{-- Kolom password (disembunyikan tapi bisa dilihat) --}} + + + {{-- Tombol Aksi --}} + + + @empty + + + + @endforelse + +
#NamaEmailRolePasswordAksi
{{ $i + 1 }}{{ $user->name }}{{ $user->email }} + @if($user->role == 'guru') + Guru + @elseif($user->role == 'wali_murid') + Wali Murid + @else + Admin + @endif + +
+ + +
+
+ Edit + +
+ @csrf + +
+ +
+ @csrf + @method('DELETE') + +
+
Belum ada akun terdaftar.
- @if(session('success')) -
{{ session('success') }}
- @endif - @if(session('error')) -
{{ session('error') }}
- @endif - - - - - - - - - - - - - - @forelse ($users as $i => $user) - - - - - - - {{-- Kolom password (disembunyikan tapi bisa dilihat) --}} - - - {{-- Tombol Aksi --}} - - - @empty - - - - @endforelse - -
#NamaEmailRolePasswordAksi
{{ $i + 1 }}{{ $user->name }}{{ $user->email }} - @if($user->role == 'guru') - Guru - @elseif($user->role == 'wali_murid') - Wali Murid - @else - Admin - @endif - -
- - -
-
- Edit - -
- @csrf - -
- -
- @csrf - @method('DELETE') - -
-
Belum ada akun terdaftar.
-
- -{{-- Script show/hide password --}} - -@endsection + {{-- Script show/hide password --}} + +@endsection \ No newline at end of file diff --git a/resources/views/admin/guru/index.blade.php b/resources/views/admin/guru/index.blade.php index 3d280fe..badb6df 100644 --- a/resources/views/admin/guru/index.blade.php +++ b/resources/views/admin/guru/index.blade.php @@ -1,71 +1,81 @@ @extends('layouts.app') @section('content') -
- -
- -
-
-

- Data Guru -

-

Kelola informasi tenaga pengajar PAUD.

+
+ +
+ +
+
+
+

+ Data Guru +

+

Kelola informasi tenaga pengajar PAUD.

+
+
- -
-
-
- - - - - - - - - - - - - @forelse ($gurus as $i => $guru) - - - - - - - - - @empty - - - - @endforelse - -
#Nama GuruEmailNo HPJenis GuruAksi
{{ $i + 1 }}{{ $guru->nama_guru ?? '-' }}{{ $guru->email ?? '-' }}{{ $guru->no_hp ?? '-' }} - {{-- Logic tampilan badge --}} - @if($guru->jenis_guru == 'guru_kelas') - Guru Kelas - @elseif($guru->jenis_guru == 'shadow_abk') - Shadow ABK - @else - - - @endif - - Edit -
- @csrf - @method('DELETE') - -
-
Belum ada data guru
+
+
+ + + + + + + + + + + + + @forelse ($gurus as $i => $guru) + + + + + + + + + @empty + + + + @endforelse + +
#Nama GuruEmailNo HPJenis GuruAksi
{{ $i + 1 }}{{ $guru->nama_guru ?? '-' }}{{ $guru->email ?? '-' }}{{ $guru->no_hp ?? '-' }} + {{-- Logic tampilan badge --}} + @if($guru->jenis_guru == 'guru_kelas') + Guru + Kelas + @elseif($guru->jenis_guru == 'shadow_abk') + Shadow + ABK + @else + - + @endif + + Edit +
+ @csrf + @method('DELETE') + +
+
Belum ada data guru
+
+
-
-
@endsection \ No newline at end of file diff --git a/resources/views/admin/pengumuman/index.blade.php b/resources/views/admin/pengumuman/index.blade.php index c713f81..031c403 100644 --- a/resources/views/admin/pengumuman/index.blade.php +++ b/resources/views/admin/pengumuman/index.blade.php @@ -1,62 +1,71 @@ @extends('layouts.app') @section('content') -
- -
- -
-
-

- Menu Pengumuman -

-

Kelola informasi dan pengumuman untuk seluruh pihak.

+
+ +
+ +
+
+
+

+ Menu Pengumuman +

+

Kelola informasi dan pengumuman untuk seluruh + pihak.

+
+
- -
-
-
- - - - - - - - - - - - @foreach ($pengumuman as $i => $p) - - - - - - - - @endforeach - -
#JudulTanggalStatusAksi
{{ $i+1 }}{{ $p->judul }} - {{ $p->tanggal_mulai }} - {{ $p->tanggal_selesai }} - - - {{ $p->status ? 'Aktif' : 'Nonaktif' }} - - - Edit -
- @csrf - @method('DELETE') - -
-
+
+
+ + + + + + + + + + + + @foreach ($pengumuman as $i => $p) + + + + + + + + @endforeach + +
#JudulTanggalStatusAksi
{{ $i + 1 }}{{ $p->judul }} + {{ $p->tanggal_mulai }} - {{ $p->tanggal_selesai }} + + + {{ $p->status ? 'Aktif' : 'Nonaktif' }} + + + Edit +
+ @csrf + @method('DELETE') + +
+
+
+
-
-
-@endsection +@endsection \ No newline at end of file diff --git a/resources/views/admin/penjemputan/index.blade.php b/resources/views/admin/penjemputan/index.blade.php index 3356573..5dc90cc 100644 --- a/resources/views/admin/penjemputan/index.blade.php +++ b/resources/views/admin/penjemputan/index.blade.php @@ -1,82 +1,96 @@ @extends('layouts.app') @section('content') -
-
-
-

- Log Penjemputan -

-

Daftar riwayat penjemputan siswa (Real-time).

+
+
+
+

+ Log + Penjemputan +

+

Daftar riwayat penjemputan siswa (Real-time).

+
+ +
+ Hari Ini: + {{ $logs->where('waktu_jemput', '>=', now()->today())->count() }} +
- -
- Hari Ini: {{ $logs->where('waktu_jemput', '>=', now()->today())->count() }} -
-
-
- - - - - - - - - - - - @forelse($logs as $log) - - - - - - - - - - +
+
Waktu JemputNama SiswaNama PenjemputStatus HubunganAksi
-
- {{ \Carbon\Carbon::parse($log->waktu_jemput)->timezone('Asia/Jakarta')->format('H:i') }} WIB -
-
- {{ \Carbon\Carbon::parse($log->waktu_jemput)->timezone('Asia/Jakarta')->format('d M Y') }} -
-
-
{{ $log->siswa->nama_siswa ?? 'Siswa Terhapus' }}
-
NIS: {{ $log->siswa->nis ?? '-' }}
-
- {{ $log->nama_penjemput }} - - - {{ $log->status_hubungan }} - - -
- @csrf - @method('DELETE') - -
-
+ + + + + + + + + + @forelse($logs as $log) + + + + + + + + + + + @empty - - - + + + @endforelse
Waktu JemputNama SiswaNama PenjemputStatus HubunganAksi
+
+ {{ \Carbon\Carbon::parse($log->waktu_jemput)->timezone('Asia/Jakarta')->format('H:i') }} WIB +
+
+ {{ \Carbon\Carbon::parse($log->waktu_jemput)->timezone('Asia/Jakarta')->format('d M Y') }} +
+
+
{{ $log->siswa->nama_siswa ?? 'Siswa Terhapus' }}
+
NIS: {{ $log->siswa->nis ?? '-' }}
+
+ {{ $log->nama_penjemput }} + + + {{ $log->status_hubungan }} + + +
+ @csrf + @method('DELETE') + +
+
-
- -

Belum ada data penjemputan hari ini.

-
-
+
+ + + +

Belum ada data penjemputan hari ini.

+
+
-
+
@endsection \ No newline at end of file diff --git a/resources/views/admin/perkembangan/index.blade.php b/resources/views/admin/perkembangan/index.blade.php index 194f019..c13bccd 100644 --- a/resources/views/admin/perkembangan/index.blade.php +++ b/resources/views/admin/perkembangan/index.blade.php @@ -1,72 +1,79 @@ @extends('layouts.app') @section('content') -
- -
- -
-
-

- Laporan Perkembangan -

-

Pilih siswa untuk melihat Catatan Anekdot, Hasil Karya, dan Ceklis.

+
+ +
+ +
+
+
+

+ Laporan Perkembangan +

+

Pilih siswa untuk melihat Catatan Anekdot, + Hasil Karya, dan Ceklis.

+
+
+ Total Siswa: {{ $siswas->count() }} +
-
- Total Siswa: {{ $siswas->count() }} + +
+
+ + + + + + + + + + + @forelse($siswas as $index => $siswa) + + + + + + + + + + @empty + + + + @endforelse + +
NoNISNama SiswaAksi
{{ $index + 1 }} + + {{ $siswa->nis ?? '-' }} + + + {{ $siswa->nama_siswa }} + + {{-- PERBAIKAN: Hapus 'admin.' jadi 'perkembangan.show' --}} + + 📂 Buka Rapot + +
+
+ 📭 +

Belum ada data siswa.

+
+
+
+
+ +
+ © {{ date('Y') }} PAUD Aisyiyah Monitoring System
- -
-
- - - - - - - - - - - @forelse($siswas as $index => $siswa) - - - - - - - - - - @empty - - - - @endforelse - -
NoNISNama SiswaAksi
{{ $index + 1 }} - - {{ $siswa->nis ?? '-' }} - - - {{ $siswa->nama_siswa }} - - {{-- PERBAIKAN: Hapus 'admin.' jadi 'perkembangan.show' --}} - - 📂 Buka Rapot - -
-
- 📭 -

Belum ada data siswa.

-
-
-
-
- -
- © {{ date('Y') }} PAUD Aisyiyah Monitoring System -
-
@endsection \ No newline at end of file diff --git a/resources/views/admin/siswa/index.blade.php b/resources/views/admin/siswa/index.blade.php index 508cfc2..b7ac282 100644 --- a/resources/views/admin/siswa/index.blade.php +++ b/resources/views/admin/siswa/index.blade.php @@ -1,106 +1,117 @@ @extends('layouts.app') @section('content') -
- -
- -
-
-

- Data Peserta Didik -

-

Manajemen data peserta didik PAUD.

+
+ +
+ +
+
+
+

+ Data Peserta Didik +

+

Manajemen data peserta didik PAUD.

+
+
-
- - Tambah Siswa - + +
+ + @if(session('success')) + + @endif + +
+ + + + + + + + + + + + + + @forelse($siswas as $index => $siswa) + + + + + + + + + + + + + + + + @empty + + + + @endforelse + +
NoNIS / NISNNama SiswaL/PTTLWali Murid / AlamatAksi
{{ $index + 1 }} +
{{ $siswa->nis ?? '-' }}
+
{{ $siswa->nisn ?? '-' }}
+
{{ $siswa->nama_siswa }} + + {{ $siswa->jenis_kelamin }} + + + {{ $siswa->tempat_lahir }}, {{ date('d-m-Y', strtotime($siswa->tanggal_lahir)) }} + + @if($siswa->wali_murid) +
{{ $siswa->wali_murid->nama_wali }}
+ {{-- Tampilkan Alamat dari Wali Murid --}} +
🏠 {{ Str::limit($siswa->wali_murid->alamat, 30) }} +
+ @if(!empty($siswa->wali_murid->no_hp) && $siswa->wali_murid->no_hp != '-') +
📞 {{ $siswa->wali_murid->no_hp }}
+ @endif + @else + ⚠️ Belum diset + @endif +
+
+ + Edit + +
+ @csrf + @method('DELETE') + +
+
+
+ Belum ada data siswa. +
+
- -
- - @if(session('success')) - - @endif - -
- - - - - - - - - - - - - - @forelse($siswas as $index => $siswa) - - - - - - - - - - - - - - - - @empty - - - - @endforelse - -
NoNIS / NISNNama SiswaL/PTTLWali Murid / AlamatAksi
{{ $index + 1 }} -
{{ $siswa->nis ?? '-' }}
-
{{ $siswa->nisn ?? '-' }}
-
{{ $siswa->nama_siswa }} - - {{ $siswa->jenis_kelamin }} - - - {{ $siswa->tempat_lahir }}, {{ date('d-m-Y', strtotime($siswa->tanggal_lahir)) }} - - @if($siswa->wali_murid) -
{{ $siswa->wali_murid->nama_wali }}
- {{-- Tampilkan Alamat dari Wali Murid --}} -
🏠 {{ Str::limit($siswa->wali_murid->alamat, 30) }}
- @if(!empty($siswa->wali_murid->no_hp) && $siswa->wali_murid->no_hp != '-') -
📞 {{ $siswa->wali_murid->no_hp }}
- @endif - @else - ⚠️ Belum diset - @endif -
-
- - Edit - -
- @csrf - @method('DELETE') - -
-
-
- Belum ada data siswa. -
-
-
-
@endsection \ No newline at end of file diff --git a/resources/views/admin/wali/create.blade.php b/resources/views/admin/wali/create.blade.php index e9303b0..e4c6fcb 100644 --- a/resources/views/admin/wali/create.blade.php +++ b/resources/views/admin/wali/create.blade.php @@ -39,6 +39,22 @@
+ +
+ + +
diff --git a/resources/views/admin/wali/edit.blade.php b/resources/views/admin/wali/edit.blade.php index 517fa01..47be722 100644 --- a/resources/views/admin/wali/edit.blade.php +++ b/resources/views/admin/wali/edit.blade.php @@ -1,64 +1,90 @@ @extends('layouts.app') @section('content') -
-
-

✏️ Edit Wali Murid

- ← Kembali -
- - @if ($errors->any()) - - @endif - - {{-- PERHATIKAN: DI SINI KITA PAKAI $data (BUKAN $wali_murid) --}} -
- @csrf - @method('PUT') - -
- - {{-- PERHATIKAN: value="{{ old('nama_wali', $data->nama_wali) }}" --}} - +
+
+

✏️ Edit Wali Murid

+ ← Kembali
-
- - -
- -
- - -
+ @if ($errors->any()) + + @endif -
- - -
+ {{-- PERHATIKAN: DI SINI KITA PAKAI $data (BUKAN $wali_murid) --}} + + @csrf + @method('PUT') -
-
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+

🔐 Pengaturan Akun Login

+ +
+
+ + +
+
+ + +

*Isi hanya jika ingin mengganti password login.

+
+
+
+ +
+ -
- -
+ 💾 Simpan Perubahan + +
+ +
@endsection \ No newline at end of file diff --git a/resources/views/admin/wali/index.blade.php b/resources/views/admin/wali/index.blade.php index cd90284..b60c9da 100644 --- a/resources/views/admin/wali/index.blade.php +++ b/resources/views/admin/wali/index.blade.php @@ -1,79 +1,89 @@ @extends('layouts.app') @section('content') -
- -
- -
-
-

- Data Wali Murid -

-

Kelola informasi orang tua / wali peserta didik.

-
- -
- -
- {{-- Alert Merah untuk Error --}} - @if(session('error')) -