Lanjut Flutter (masih belum)

🟢 Dashboard & Master Data (Selesai/Hampir Selesai)
[x] Data Guru: (Tambah, Edit, Hapus) — Sudah ada di GuruController.

[x] Data Wali Murid: (Tambah, Edit, Hapus) — Sudah ada di database.

[x] Data Siswa: (Relasi ke Wali & Kelas) — Sudah ada di database.

[x] Manajemen Kelas: (Gatotkaca, dll).

🟠 Fitur Monitoring (Laporan & Penjemputan)
Ini adalah fitur yang datanya datang dari Mobile, tapi Admin harus bisa lihat:

[ ] Monitoring Laporan Perkembangan:

Tampilan List Laporan (sudah dibuatkan kodenya tadi).

Fungsi Hapus (untuk moderasi data).

Note: Di web tidak ada tombol "Tambah", karena itu tugas Guru di HP.

[ ] Monitoring Log Penjemputan:

Tampilan Log real-time (jam jemput, siapa yang jemput).

Filter berdasarkan "Hari Ini" (supaya tidak menumpuk).

Tombol input manual (untuk jaga-jaga kalau Wali lupa bawa HP).

🔴 Fitur Sistem & Akun (Wajib Ada)
Tanpa ini, Guru dan Wali tidak bisa login ke aplikasi Flutter:

[ ] User Account Generator:

Setiap Guru dan Wali harus punya baris di tabel users.

(Gunakan Seeder yang saya kasih tadi untuk membuatkan akun masal).

[ ] Role Management:

Memastikan siapa yang admin, siapa yang guru, siapa yang wali.

[ ] API Authentication (Sanctum):

"Pintu" agar Flutter bisa login (sudah saya kasih kodenya di AuthController).

📋 Ringkasan File yang Belum Kamu Buat/Cek:
View Log Penjemputan: resources/views/admin/penjemputan/index.blade.php (tadi sempat tertunda).

API Routes: routes/api.php (untuk koneksi Flutter).

Seeder Akun: database/seeders/UserGeneratorSeeder.php (supaya ada akun buat ngetes login di HP).

Saran saya: Pastikan kamu sudah membuat View Log Penjemputan (Langkah terakhir di chat sebelumnya) supaya tampilan Web-mu tidak ada yang kurang saat didemokan.
This commit is contained in:
ghozahimma65 2026-02-04 20:34:32 +07:00
parent b646cf0d61
commit ad1d7b2b93
25 changed files with 523 additions and 361 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -10,8 +10,8 @@ class GuruController extends Controller
{
public function index()
{
$gurus = Guru::orderBy('created_at', 'desc')->get();
return view('admin.guru.index', compact('gurus'));
$gurus = Guru::orderBy('created_at', 'desc')->get();
return view('admin.guru.index', compact('gurus'));
}
public function create()
@ -21,11 +21,12 @@ public function create()
public function store(Request $request)
{
// Validasi disesuaikan dengan kolom database
$request->validate([
'nama_guru' => 'required|string|max:100',
'email' => 'nullable|email|max:100',
'no_hp' => 'nullable|string|max:20',
'bidang' => 'nullable|string|max:100',
'nama_guru' => 'required|string|max:100',
'email' => 'nullable|email|max:100',
'no_hp' => 'nullable|string|max:20',
'jenis_guru' => 'required|in:guru_kelas,shadow_abk', // UBAH 'bidang' JADI 'jenis_guru'
]);
Guru::create($request->all());
@ -41,10 +42,10 @@ public function edit(Guru $guru)
public function update(Request $request, Guru $guru)
{
$request->validate([
'nama_guru' => 'required|string|max:100',
'email' => 'nullable|email|max:100',
'no_hp' => 'nullable|string|max:20',
'bidang' => 'nullable|string|max:100',
'nama_guru' => 'required|string|max:100',
'email' => 'nullable|email|max:100',
'no_hp' => 'nullable|string|max:20',
'jenis_guru' => 'required|in:guru_kelas,shadow_abk',
]);
$guru->update($request->all());

View File

@ -4,91 +4,68 @@
use App\Http\Controllers\Controller;
use App\Models\Siswa;
use App\Models\Kelas;
use App\Models\WaliMurid;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class SiswaController extends Controller
{
public function index()
{
$siswas = Siswa::with(['waliMurid', 'kelas'])->orderBy('created_at', 'desc')->get();
// Ambil data siswa + data walinya (supaya tidak berat query-nya)
$siswas = Siswa::with('wali')->latest()->get();
return view('admin.siswa.index', compact('siswas'));
}
public function create()
{
$kelas = Kelas::all();
$wali_murids = WaliMurid::all();
return view('admin.siswa.create', compact('kelas', 'wali_murids'));
// Ambil data wali untuk dropdown pilihan
$walis = WaliMurid::orderBy('nama_wali', 'asc')->get();
return view('admin.siswa.create', compact('walis'));
}
public function store(Request $request)
{
$validated = $request->validate([
'nama' => 'required|string|max:255',
'tempat_lahir' => 'nullable|string|max:255',
'tanggal_lahir' => 'nullable|date',
'alamat' => 'nullable|string',
'kelas_id' => 'nullable|exists:kelas,id',
'wali_id' => 'nullable|exists:wali_murids,id',
'keterangan' => 'nullable|string',
'foto' => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
]);
if ($request->hasFile('foto')) {
$validated['foto'] = $request->file('foto')->store('fotosiswa', 'public');
}
Siswa::create($validated);
return redirect()->route('siswa.index')->with('success', 'Data peserta didik berhasil ditambahkan.');
}
public function edit(Siswa $siswa)
{
$kelas = Kelas::all();
$wali_murids = WaliMurid::all();
return view('admin.siswa.edit', compact('siswa', 'kelas', 'wali_murids'));
}
public function update(Request $request, Siswa $siswa)
{
$request->validate([
'nama' => 'required|string|max:255',
'tempat_lahir' => 'nullable|string|max:100',
'tanggal_lahir' => 'nullable|date',
'kelas_id' => 'nullable|exists:kelas,id',
'wali_id' => 'nullable|exists:wali_murids,id',
'foto' => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
'nama_siswa' => 'required|string|max:100',
'wali_id' => 'required|exists:wali_murids,id', // Wajib pilih wali yg valid
'jenis_kelamin' => 'required|in:L,P',
'tempat_lahir' => 'required|string',
'tanggal_lahir' => 'required|date',
]);
// simpan foto baru kalau diupload
if ($request->hasFile('foto')) {
$fotoPath = $request->file('foto')->store('foto_siswa', 'public');
$siswa->foto = $fotoPath;
}
// update data siswa
$siswa->update([
'nama' => $request->nama,
'tempat_lahir' => $request->tempat_lahir,
'tanggal_lahir' => $request->tanggal_lahir,
'kelas_id' => $request->kelas_id,
'wali_id' => $request->wali_id,
]);
return redirect()->route('siswa.index')->with('success', 'Data siswa berhasil diperbarui.');
Siswa::create($request->all());
return redirect()->route('siswa.index')->with('success', 'Data Siswa berhasil ditambahkan.');
}
public function destroy(Siswa $siswa)
public function edit($id)
{
if ($siswa->foto && Storage::disk('public')->exists($siswa->foto)) {
Storage::disk('public')->delete($siswa->foto);
}
$siswa->delete();
return redirect()->route('siswa.index')->with('success','Siswa berhasil dihapus');
$siswa = Siswa::findOrFail($id);
$walis = WaliMurid::orderBy('nama_wali', 'asc')->get();
return view('admin.siswa.edit', compact('siswa', 'walis'));
}
}
public function update(Request $request, $id)
{
$siswa = Siswa::findOrFail($id);
$request->validate([
'nama_siswa' => 'required|string|max:100',
'wali_id' => 'required|exists:wali_murids,id',
'jenis_kelamin' => 'required|in:L,P',
'tempat_lahir' => 'required|string',
'tanggal_lahir' => 'required|date',
]);
$siswa->update($request->all());
return redirect()->route('siswa.index')->with('success', 'Data Siswa berhasil diperbarui.');
}
public function destroy($id)
{
$siswa = Siswa::findOrFail($id);
$siswa->delete();
return redirect()->route('siswa.index')->with('success', 'Data Siswa berhasil dihapus.');
}
}

View File

@ -10,51 +10,66 @@ class WaliMuridController extends Controller
{
public function index()
{
$wali_murids = WaliMurid::orderBy('created_at', 'desc')->get();
return view('admin.wali_murid.index', compact('wali_murids'));
$walis = WaliMurid::latest()->get();
return view('admin.wali.index', compact('walis'));
}
public function create()
{
return view('admin.wali_murid.create');
return view('admin.wali.create');
}
public function store(Request $request)
{
$request->validate([
'nama_wali' => 'required|string|max:100',
'email' => 'nullable|email|max:100',
'no_hp' => 'nullable|string|max:20',
'alamat' => 'nullable|string|max:255',
'no_hp' => 'nullable|string|max:20',
'alamat' => 'nullable|string',
]);
WaliMurid::create($request->only(['nama_wali', 'email', 'no_hp', 'alamat']));
return redirect()->route('wali-murid.index')->with('success', 'Data wali murid berhasil ditambahkan.');
}
public function edit(WaliMurid $wali_murid)
{
return view('admin.wali_murid.edit', compact('wali_murid'));
WaliMurid::create($request->all());
return redirect()->route('wali-murid.index')->with('success', 'Data Wali Murid berhasil ditambahkan.');
}
public function update(Request $request, WaliMurid $wali_murid)
public function edit($id)
{
$wali = WaliMurid::findOrFail($id);
return view('admin.wali.edit', compact('wali'));
}
public function update(Request $request, $id)
{
$wali = WaliMurid::findOrFail($id);
$request->validate([
'nama_wali' => 'required|string|max:100',
'email' => 'nullable|email|max:100',
'no_hp' => 'nullable|string|max:20',
'alamat' => 'nullable|string|max:255',
'no_hp' => 'nullable|string|max:20',
'alamat' => 'nullable|string',
]);
$wali_murid->update($request->all());
$wali->update($request->all());
return redirect()->route('wali-murid.index')->with('success', 'Data wali murid berhasil diperbarui.');
return redirect()->route('wali-murid.index')->with('success', 'Data Wali Murid berhasil diperbarui.');
}
public function destroy(WaliMurid $wali_murid)
public function destroy($id)
{
$wali_murid->delete();
$wali = WaliMurid::findOrFail($id);
return redirect()->route('wali-murid.index')->with('success', 'Data wali murid berhasil dihapus.');
// --- LOGIC AMAN (Mencegah Error Database) ---
// Cek apakah wali ini punya anak didik (siswa)
// Pastikan di Model WaliMurid sudah ada relasi: public function siswas()
$jumlah_siswa = $wali->siswas()->count();
if ($jumlah_siswa > 0) {
// Jika masih punya siswa, BATALKAN hapus & beri pesan Error
return redirect()->route('wali-murid.index')->with('error', '❌ Gagal Hapus! Wali ini masih terhubung dengan ' . $jumlah_siswa . ' data Siswa. Hapus atau pindahkan data siswanya dulu.');
}
// Jika tidak punya siswa, baru boleh dihapus
$wali->delete();
return redirect()->route('wali-murid.index')->with('success', '✅ Data Wali Murid berhasil dihapus.');
}
}
}

View File

@ -9,12 +9,11 @@ class Guru extends Model
{
use HasFactory;
// kasih tahu Laravel kalau nama tabelnya "guru", bukan "gurus"
protected $table = 'guru';
protected $table = 'guru'; // Sesuai DB kamu
protected $fillable = [
'nama',
'jenis_guru',
'nama_guru', // SEBELUMNYA 'nama' (SALAH), HARUS 'nama_guru'
'jenis_guru', // SEBELUMNYA 'jenis_guru' (SUDAH BENAR TAPI INPUT FORM SALAH)
'no_hp',
'email',
'user_id',

View File

@ -1,28 +1,29 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Siswa extends Model
{
use HasFactory;
protected $table = 'siswas'; // Nama tabel di database
protected $fillable = [
'nama',
'wali_id', // Kunci Relasi ke Wali Murid
'nama_siswa',
'tempat_lahir',
'tanggal_lahir',
'alamat',
'keterangan',
'kelas_id',
'wali_id',
'foto',
'jenis_kelamin', // L atau P
'tanggal_masuk', // Opsional
];
public function kelas()
{
return $this->belongsTo(Kelas::class);
}
public function waliMurid()
/**
* Relasi: Setiap Siswa PASTI punya satu Wali Murid
*/
public function wali()
{
return $this->belongsTo(WaliMurid::class, 'wali_id');
}

View File

@ -9,18 +9,24 @@ class WaliMurid extends Model
{
use HasFactory;
protected $table = 'wali_murids';
protected $table = 'wali_murids'; // Default laravel biasanya plural
protected $fillable = [
'nama_wali',
'no_hp',
'email',
'alamat',
'user_id',
'nama_wali', // Pastikan kolom di DB 'nama_wali', bukan 'nama'
'no_hp',
'alamat',
'pekerjaan', // Opsional, jaga-jaga kalau butuh
];
public function user()
{
return $this->belongsTo(User::class);
}
// Relasi ke Siswa (Satu wali bisa punya banyak anak)
public function siswas()
{
return $this->hasMany(Siswa::class, 'wali_id');
}
}

View File

@ -6,25 +6,22 @@
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
public function up()
{
Schema::create('wali_murids', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->foreignId('user_id')->nullable()->constrained('users')->onDelete('set null');
$table->string('nama_wali'); // Sesuai PDF "Nama Orang Tua"
$table->string('no_hp')->nullable();
$table->text('alamat')->nullable(); // Sesuai PDF "Alamat"
$table->string('pekerjaan')->nullable();
$table->string('alamat')->nullable();
$table->decimal('lokasi_lat', 10, 7)->nullable();
$table->decimal('lokasi_lng', 10, 7)->nullable();
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
public function down(): void
public function down()
{
Schema::dropIfExists('wali_murids');
}

View File

@ -6,24 +6,25 @@
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
public function up()
{
Schema::create('guru', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
$table->string('bidang')->nullable();
$table->timestamps();
});
Schema::create('guru', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->nullable()->constrained('users')->onDelete('set null');
$table->string('nama_guru');
$table->enum('jenis_guru', ['guru_kelas', 'shadow_abk']);
$table->string('nip')->nullable();
$table->string('no_hp')->nullable();
$table->string('email')->nullable(); // Wajib ada biar ga error seeder
$table->text('alamat')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
public function down()
{
Schema::dropIfExists('gurus');
Schema::dropIfExists('guru');
}
};
};

View File

@ -6,31 +6,24 @@
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
public function up()
{
Schema::create('siswas', function (Blueprint $table) {
$table->id();
$table->string('nama');
$table->string('nis')->unique();
$table->date('tanggal_lahir');
$table->unsignedBigInteger('kelas_id');
$table->unsignedBigInteger('wali_id');
$table->string('foto')->nullable();
$table->timestamps();
$table->foreign('kelas_id')->references('id')->on('kelas')->onDelete('cascade');
$table->foreign('wali_id')->references('id')->on('wali_murids')->onDelete('cascade');
});
Schema::create('siswas', function (Blueprint $table) {
$table->id();
$table->foreignId('wali_id')->constrained('wali_murids')->onDelete('cascade');
$table->string('nama_siswa'); // Sesuai PDF "Nama Anak"
$table->string('tempat_lahir'); // Sesuai PDF "Tempat"
$table->date('tanggal_lahir'); // Sesuai PDF "Tgl Lahir"
$table->enum('jenis_kelamin', ['L', 'P']);
$table->date('tanggal_masuk')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
public function down()
{
Schema::dropIfExists('siswas');
}
};
};

View File

@ -2,15 +2,33 @@
namespace Database\Seeders;
use App\Models\User;
use Illuminate\Database\Seeder;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
$this->call([
MasterSeeder::class,
// 1. Buat Akun Admin (Supaya kamu bisa Login)
// Kita buat manual di sini biar tidak error pakai seeder lama
User::create([
'name' => 'Administrator',
'email' => 'admin@admin.com',
'password' => Hash::make('password'), // Password default
'role' => 'admin',
]);
// 2. Jalankan Seeder Data Sekolah (Sesuai PDF)
$this->call([
GuruSeeder::class, // Data Guru (Fixed)
WaliMuridSeeder::class, // Data Wali (Fixed)
SiswaSeeder::class, // Data Siswa (Fixed)
]);
// CATATAN: Jangan panggil MasterSeeder lagi karena kodenya usang.
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
class GuruSeeder extends Seeder
{
public function run()
{
$data = [
// Guru Kelas
['nama_guru' => 'Ibu. Junita Dhanesti, S.Pd', 'jenis_guru' => 'guru_kelas'],
['nama_guru' => 'Ibu. Afif Wais Al Qorni, S.Pd.', 'jenis_guru' => 'guru_kelas'],
['nama_guru' => 'Ibu. Anisa Nur Pratama, S.Psi', 'jenis_guru' => 'guru_kelas'],
// Guru Shadow ABK
['nama_guru' => 'Ibu. Ellyse Clara Nargata', 'jenis_guru' => 'shadow_abk'],
['nama_guru' => 'Ibu. Efa Nur Azizah', 'jenis_guru' => 'shadow_abk'],
['nama_guru' => 'Ibu. Istik Sundari, S.Pd.', 'jenis_guru' => 'shadow_abk'],
];
foreach ($data as $d) {
DB::table('guru')->insert([
'nama_guru' => $d['nama_guru'],
'jenis_guru' => $d['jenis_guru'],
'email' => null,
'no_hp' => '-',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
]);
}
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\Siswa;
use App\Models\WaliMurid;
class SiswaSeeder extends Seeder
{
public function run()
{
// Format: [Nama Anak, Nama Orang Tua, Tempat Lahir, Tgl Lahir (YYYY-MM-DD), JK]
$data_siswa = [
['Achazia Nakhi Shankara', 'Tomi Puspita Aji', 'Kota Madiun', '2021-03-30', 'L'],
['Zayn Risky Putra Setyawan', 'Yonna Setyawan', 'Kota Madiun', '2020-04-07', 'L'],
['Zain Mizyal Alkhalifi Luis', 'Taufiq Rahman Luis', 'Kota Madiun', '2022-02-27', 'L'],
['Yafiq Hasan Besari', 'Andika Bayu', 'Berau', '2020-02-19', 'L'],
['Azia Nurafni Shidqia', 'Masita Sari', 'Madiun', '2019-01-14', 'P'],
['Zhafir Reza Arifa Putra', 'Ayu Trisnawati', 'Madiun', '2019-05-05', 'L'],
['Alliemsa Azka Ayyub Anggoro', 'Alliemsa Anggi Putra', 'Madiun', '2018-07-20', 'L'],
['Samudra Zikru Al Fakih', 'Renny Wulandari', 'Malang', '2018-01-24', 'L'],
// Data tambahan jika ada di PDF tapi terpotong, disesuaikan dengan data wali yg ada
['Arsyad', 'Miftakhul Jannah', 'Madiun', '2020-05-10', 'L'],
['Almeera', 'Ika Septina', 'Madiun', '2020-08-15', 'P'],
];
foreach ($data_siswa as $ds) {
// Cari ID Wali berdasarkan Nama Orang Tua
$wali = WaliMurid::where('nama_wali', 'LIKE', '%' . $ds[1] . '%')->first();
if ($wali) {
Siswa::create([
'wali_id' => $wali->id,
'nama_siswa' => $ds[0],
'tempat_lahir' => $ds[2],
'tanggal_lahir' => $ds[3],
'jenis_kelamin' => $ds[4],
]);
}
}
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
class WaliMuridSeeder extends Seeder
{
public function run()
{
$walis = [
['nama' => 'Tomi Puspita Aji', 'alamat' => 'Jl. Ciliwung No. 22 RT 47 RW 15 Taman'],
['nama' => 'Yonna Setyawan', 'alamat' => 'Jl. Jambu Kembar 1 No. 1 CRT 20 RW 07 Taman Kota Madiun'],
['nama' => 'Taufiq Rahman Luis', 'alamat' => 'Griya Kencana Wungu Blok C No. 12'], // Asumsi dari data sebelumnya
['nama' => 'Andika Bayu', 'alamat' => 'Jl. Pilang Mudya 3 / 8'],
['nama' => 'Masita Sari', 'alamat' => 'Dsn. Butan Rt 035 Rw 005 Ds. Krandegan Kec. Kebonsari'],
['nama' => 'Ayu Trisnawati', 'alamat' => 'Rt 018 Rw 004 Jl. Remora Mas Blok O No. 7 Perum Telaga Mas'],
['nama' => 'Alliemsa Anggi Putra', 'alamat' => 'Jl. Panglima Sudirman No. 75 RT 37 RW 12 Taman Kota Madiun'],
['nama' => 'Renny Wulandari', 'alamat' => 'Rt 033 Rw 001 Jl. Khairil Anwar Gang Palm 1/284 Ds. Badean'],
['nama' => 'Anggieta', 'alamat' => 'Dusun II Ds. Sukolilo Kec Jiwan Kab Madiun'],
['nama' => 'Miftakhul Jannah', 'alamat' => 'Jl. Sasono Mulyo No. 18 Sogaten'],
['nama' => 'Ika Septina', 'alamat' => 'Jl. Pasopati No. 18 Josenan'],
];
foreach ($walis as $w) {
DB::table('wali_murids')->insert([
'nama_wali' => $w['nama'],
'alamat' => $w['alamat'],
'no_hp' => '-',
'created_at' => Carbon::now(),
'updated_at' => Carbon::now(),
]);
}
}
}

View File

@ -44,10 +44,10 @@
{{-- Kolom password (disembunyikan tapi bisa dilihat) --}}
<td class="p-3 border text-center">
<div class="relative inline-block">
<input
type="password"
value="123456"
readonly
<input
type="password"
value="123456"
readonly
class="border rounded-lg px-2 py-1 text-center bg-gray-100 text-sm w-24 password-field"
>
<button type="button" class="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 toggle-password">
@ -59,12 +59,12 @@ class="border rounded-lg px-2 py-1 text-center bg-gray-100 text-sm w-24 password
{{-- Tombol Aksi --}}
<td class="p-3 border text-center space-x-2">
<a href="{{ route('akun.edit', $user->id) }}" class="bg-blue-500 text-white px-3 py-1 rounded hover:bg-blue-600">Edit</a>
<form action="{{ route('akun.reset', $user->id) }}" method="POST" class="inline">
@csrf
<button type="submit" class="bg-yellow-500 text-white px-3 py-1 rounded hover:bg-yellow-600">Reset</button>
</form>
<form action="{{ route('akun.destroy', $user->id) }}" method="POST" onsubmit="return confirm('Yakin mau hapus akun ini?')" class="inline">
@csrf
@method('DELETE')

View File

@ -8,13 +8,18 @@
@csrf
<div class="mb-4">
<label class="block text-gray-700">Nama</label>
<label class="block text-gray-700">Nama Guru</label>
{{-- Name harus 'nama_guru', bukan 'nama' --}}
<input type="text" name="nama_guru" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300" required>
</div>
<div class="mb-4">
<label class="block text-gray-700">Bidang</label>
<input type="text" name="bidang" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300">
<label class="block text-gray-700">Jenis Guru</label>
{{-- Ganti input text 'bidang' jadi Select 'jenis_guru' sesuai Enum DB --}}
<select name="jenis_guru" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300">
<option value="guru_kelas">Guru Kelas</option>
<option value="shadow_abk">Shadow ABK</option>
</select>
</div>
<div class="mb-4">
@ -30,4 +35,4 @@
<button type="submit" class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600">Simpan</button>
</form>
</div>
@endsection
@endsection

View File

@ -14,7 +14,7 @@
<th class="p-2">Nama Guru</th>
<th class="p-2">Email</th>
<th class="p-2">No HP</th>
<th class="p-2">Bidang</th>
<th class="p-2">Jenis Guru</th>
<th class="p-2">Aksi</th>
</tr>
</thead>
@ -22,10 +22,19 @@
@forelse ($gurus as $i => $guru)
<tr class="border-b hover:bg-gray-50">
<td class="p-2">{{ $i + 1 }}</td>
<td class="p-2">{{ $guru->nama_guru ?? '-' }}</td>
<td class="p-2 font-medium">{{ $guru->nama_guru ?? '-' }}</td>
<td class="p-2">{{ $guru->email ?? '-' }}</td>
<td class="p-2">{{ $guru->no_hp ?? '-' }}</td>
<td class="p-2">{{ $guru->bidang ?? '-' }}</td>
<td class="p-2">
{{-- Logic tampilan badge --}}
@if($guru->jenis_guru == 'guru_kelas')
<span class="bg-blue-100 text-blue-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">Guru Kelas</span>
@elseif($guru->jenis_guru == 'shadow_abk')
<span class="bg-yellow-100 text-yellow-800 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded">Shadow ABK</span>
@else
-
@endif
</td>
<td class="p-2 space-x-2">
<a href="{{ route('guru.edit', $guru->id) }}" class="text-blue-500 hover:underline">Edit</a>
<form action="{{ route('guru.destroy', $guru->id) }}" method="POST" class="inline" onsubmit="return confirm('Yakin hapus data ini?');">
@ -43,4 +52,4 @@
</tbody>
</table>
</div>
@endsection
@endsection

View File

@ -0,0 +1,42 @@
@extends('layouts.app')
@section('content')
<div class="bg-white shadow-md rounded-lg p-6">
<div class="flex justify-between items-center mb-4">
<div>
<h1 class="text-xl font-semibold text-gray-700">🚸 Monitoring Penjemputan</h1>
<p class="text-sm text-gray-500">Data masuk secara real-time dari aplikasi mobile.</p>
</div>
</div>
<div class="overflow-x-auto">
<table class="w-full border-collapse">
<thead>
<tr class="bg-gray-800 text-white text-left">
<th class="p-3">Waktu</th>
<th class="p-3">Nama Siswa</th>
<th class="p-3">Penjemput</th>
<th class="p-3">Hubungan</th>
<th class="p-3">Status</th>
</tr>
</thead>
<tbody>
{{-- Data ini nanti otomatis muncul saat Wali klik jemput di HP --}}
@forelse ($logs as $log)
<tr class="border-b hover:bg-gray-50">
<td class="p-3 font-bold">{{ \Carbon\Carbon::parse($log->waktu_jemput)->format('H:i') }}</td>
<td class="p-3">{{ $log->siswa->nama_siswa }}</td>
<td class="p-3">{{ $log->nama_penjemput }}</td>
<td class="p-3"><span class="bg-blue-100 text-blue-700 px-2 py-1 rounded text-xs">{{ $log->hubungan }}</span></td>
<td class="p-3"><span class="text-green-600 font-bold"> Selesai</span></td>
</tr>
@empty
<tr>
<td colspan="5" class="text-center py-10 text-gray-400 italic">Belum ada aktifitas penjemputan hari ini.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
@endsection

View File

@ -2,69 +2,54 @@
@section('content')
<div class="bg-white shadow-md rounded-lg p-6 max-w-2xl mx-auto">
<h1 class="text-xl font-semibold text-gray-700 mb-4"> Tambah Peserta Didik</h1>
<h1 class="text-xl font-semibold text-gray-700 mb-4">👶 Tambah Siswa</h1>
<form action="{{ route('siswa.store') }}" method="POST" enctype="multipart/form-data">
<form action="{{ route('siswa.store') }}" method="POST">
@csrf
{{-- Dropdown Pilih Wali Murid --}}
<div class="mb-4">
<label class="block text-gray-600 font-medium mb-2">Nama Anak</label>
<input type="text" name="nama" class="w-full border border-gray-300 rounded p-2" required>
<label class="block text-gray-700 font-bold mb-2">Wali Murid (Orang Tua)</label>
<select name="wali_id" class="w-full border rounded px-3 py-2 bg-gray-50 focus:ring focus:ring-green-300" required>
<option value="">-- Pilih Orang Tua --</option>
@foreach($walis as $wali)
<option value="{{ $wali->id }}">{{ $wali->nama_wali }} - ({{ Str::limit($wali->alamat, 30) }})</option>
@endforeach
</select>
<p class="text-xs text-gray-500 mt-1">*Jika nama orang tua tidak ada, tambahkan dulu di menu Wali Murid.</p>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-gray-600 font-medium mb-2">Tempat Lahir</label>
<input type="text" name="tempat_lahir" class="w-full border border-gray-300 rounded p-2">
</div>
<div class="mb-4">
<label class="block text-gray-700">Nama Siswa</label>
<input type="text" name="nama_siswa" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300" required>
</div>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label class="block text-gray-600 font-medium mb-2">Tanggal Lahir</label>
<input type="date" name="tanggal_lahir" class="w-full border border-gray-300 rounded p-2">
<label class="block text-gray-700">Tempat Lahir</label>
<input type="text" name="tempat_lahir" class="w-full border rounded px-3 py-2" placeholder="Contoh: Madiun" required>
</div>
<div>
<label class="block text-gray-700">Tanggal Lahir</label>
<input type="date" name="tanggal_lahir" class="w-full border rounded px-3 py-2" required>
</div>
</div>
<div class="mt-4">
<label class="block text-gray-600 font-medium mb-2">Alamat</label>
<textarea name="alamat" class="w-full border border-gray-300 rounded p-2" rows="3"></textarea>
</div>
<div class="grid grid-cols-2 gap-4 mt-4">
<div>
<label class="block text-gray-600 font-medium mb-2">Kelas</label>
<select name="kelas_id" class="w-full border border-gray-300 rounded p-2">
<option value="">-- Pilih Kelas --</option>
@foreach ($kelas as $k)
<option value="{{ $k->id }}">{{ $k->nama_kelas }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-gray-600 font-medium mb-2">Wali Murid</label>
<select name="wali_id" class="w-full border border-gray-300 rounded p-2">
<option value="">-- Pilih Wali Murid --</option>
@foreach ($wali_murids as $wali)
<option value="{{ $wali->id }}">{{ $wali->nama_wali }}</option>
@endforeach
</select>
<div class="mb-4">
<label class="block text-gray-700">Jenis Kelamin</label>
<div class="flex gap-4 mt-2">
<label class="inline-flex items-center">
<input type="radio" name="jenis_kelamin" value="L" class="text-green-600" required>
<span class="ml-2">Laki-laki</span>
</label>
<label class="inline-flex items-center">
<input type="radio" name="jenis_kelamin" value="P" class="text-green-600">
<span class="ml-2">Perempuan</span>
</label>
</div>
</div>
<div class="mt-4">
<label class="block text-gray-600 font-medium mb-2">Keterangan</label>
<input type="text" name="keterangan" class="w-full border border-gray-300 rounded p-2">
</div>
<div class="mt-4">
<label class="block text-gray-600 font-medium mb-2">Foto</label>
<input type="file" name="foto" class="w-full border border-gray-300 rounded p-2">
</div>
<div class="flex justify-end mt-6">
<a href="{{ route('siswa.index') }}" class="bg-gray-400 text-white px-4 py-2 rounded hover:bg-gray-500 mr-2">Batal</a>
<button type="submit" class="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700">Simpan</button>
</div>
<button type="submit" class="bg-green-600 text-white px-6 py-2 rounded hover:bg-green-700 w-full">Simpan Data Siswa</button>
</form>
</div>
@endsection
@endsection

View File

@ -3,59 +3,59 @@
@section('content')
<div class="bg-white shadow-md rounded-lg p-6">
<div class="flex justify-between items-center mb-4">
<h1 class="text-xl font-semibold text-gray-700">📚 Data Peserta Didik</h1>
<a href="{{ route('siswa.create') }}"
class="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700 transition">
+ Tambah Siswa
</a>
<h1 class="text-xl font-semibold text-gray-700">👶 Data Peserta Didik</h1>
<a href="{{ route('siswa.create') }}" class="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700">+ Tambah Siswa</a>
</div>
<table class="w-full table-auto border-collapse">
@if(session('success'))
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4">
{{ session('success') }}
</div>
@endif
<table class="w-full border-collapse">
<thead>
<tr class="bg-green-600 text-white text-left">
<th class="p-2">#</th>
<th class="p-2">Nama Anak</th>
<th class="p-2">Tempat, Tgl Lahir</th>
<th class="p-2">Alamat</th>
<th class="p-2">Kelas</th>
<th class="p-2">Wali Murid</th>
<th class="p-2">Keterangan</th>
<th class="p-2">Foto</th>
<th class="p-2">No</th>
<th class="p-2">Nama Siswa</th>
<th class="p-2">L/P</th>
<th class="p-2">TTL</th>
<th class="p-2">Orang Tua (Wali)</th>
<th class="p-2">Aksi</th>
</tr>
</thead>
<tbody>
@forelse ($siswas as $siswa)
<tr>
<td>{{ $loop->iteration }}</td>
<td>{{ $siswa->nama }}</td>
<td>{{ $siswa->tempat_lahir }}, {{ $siswa->tanggal_lahir }}</td>
<td>{{ $siswa->alamat }}</td>
<td>{{ $siswa->kelas->nama_kelas ?? '-' }}</td>
<td>{{ $siswa->waliMurid->nama_wali ?? '-' }}</td>
<td>{{ $siswa->keterangan ?? '-' }}</td>
<td>
@if ($siswa->foto)
<img src="{{ asset('storage/' . $siswa->foto) }}" alt="{{ $siswa->nama }}" width="50">
@else
-
@endif
</td>
<td>
<a href="{{ route('siswa.edit', $siswa->id) }}" class="text-blue-600 hover:underline">Edit</a>
<form action="{{ route('siswa.destroy', $siswa->id) }}" method="POST" style="display:inline;">
@csrf
@method('DELETE')
<button type="submit" class="text-red-600 hover:underline">Hapus</button>
</form>
</td>
</tr>
@forelse ($siswas as $i => $siswa)
<tr class="border-b hover:bg-gray-50">
<td class="p-2">{{ $i + 1 }}</td>
<td class="p-2 font-bold">{{ $siswa->nama_siswa }}</td>
<td class="p-2">
<span class="badge {{ $siswa->jenis_kelamin == 'L' ? 'bg-blue-100 text-blue-800' : 'bg-pink-100 text-pink-800' }} px-2 py-1 rounded text-xs">
{{ $siswa->jenis_kelamin }}
</span>
</td>
<td class="p-2 text-sm">
{{ $siswa->tempat_lahir }}, {{ \Carbon\Carbon::parse($siswa->tanggal_lahir)->format('d-m-Y') }}
</td>
<td class="p-2">
{{-- Mengambil nama wali dari relasi --}}
{{ $siswa->wali->nama_wali ?? '⚠️ Data Wali Terhapus' }}
</td>
<td class="p-2 space-x-2">
<a href="{{ route('siswa.edit', $siswa->id) }}" class="text-blue-500 hover:underline">Edit</a>
<form action="{{ route('siswa.destroy', $siswa->id) }}" method="POST" class="inline" onsubmit="return confirm('Yakin hapus siswa ini?');">
@csrf
@method('DELETE')
<button type="submit" class="text-red-500 hover:underline">Hapus</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="10" class="text-center text-gray-500 p-4">Belum ada data siswa</td>
</tr>
<tr>
<td colspan="6" class="text-center text-gray-500 py-4">Belum ada data siswa.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@endsection
@endsection

View File

@ -4,30 +4,26 @@
<div class="bg-white shadow-md rounded-lg p-6 max-w-xl mx-auto">
<h1 class="text-xl font-semibold text-gray-700 mb-4"> Tambah Wali Murid</h1>
{{-- PERBAIKAN: route('wali-murid.store') --}}
<form action="{{ route('wali-murid.store') }}" method="POST">
@csrf
<div class="mb-4">
<label class="block text-gray-700 mb-1">Nama Wali Murid</label>
<label class="block text-gray-700">Nama Wali</label>
<input type="text" name="nama_wali" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300" required>
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-1">Email</label>
<input type="email" name="email" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300">
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-1">No HP</label>
<label class="block text-gray-700">No HP</label>
<input type="text" name="no_hp" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300">
</div>
<div class="mb-4">
<label class="block text-gray-700 mb-1">Alamat</label>
<textarea name="alamat" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300"></textarea>
<label class="block text-gray-700">Alamat</label>
<textarea name="alamat" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300" rows="3"></textarea>
</div>
<button type="submit" class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600">Simpan</button>
</form>
</div>
@endsection
@endsection

View File

@ -3,35 +3,46 @@
@section('content')
<div class="bg-white shadow-md rounded-lg p-6">
<div class="flex justify-between items-center mb-4">
<h1 class="text-xl font-semibold text-gray-700">👨‍👩‍👧 Data Wali Murid</h1>
<a href="{{ route('wali-murid.create') }}"
class="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700 transition">
+ Tambah Wali Murid
</a>
<h1 class="text-xl font-semibold text-gray-700">👪 Data Wali Murid</h1>
<a href="{{ route('wali-murid.create') }}" class="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700">+ Tambah Wali</a>
</div>
<table class="w-full table-auto border-collapse">
{{-- TAMBAHAN: Alert Merah untuk Error --}}
@if(session('error'))
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert">
<strong class="font-bold">Error!</strong>
<span class="block sm:inline">{{ session('error') }}</span>
</div>
@endif
{{-- Alert Hijau untuk Sukses --}}
@if(session('success'))
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert">
<strong class="font-bold">Sukses!</strong>
<span class="block sm:inline">{{ session('success') }}</span>
</div>
@endif
<table class="w-full border-collapse">
<thead>
<tr class="bg-green-600 text-white text-left">
<th class="p-2">#</th>
<th class="p-2">Nama Wali Murid</th>
<th class="p-2">Email</th>
<th class="p-2">No</th>
<th class="p-2">Nama Wali</th>
<th class="p-2">No HP</th>
<th class="p-2">Alamat</th>
<th class="p-2">Aksi</th>
</tr>
</thead>
<tbody>
@forelse($wali_murids as $i => $wali)
@forelse ($walis as $i => $wali)
<tr class="border-b hover:bg-gray-50">
<td class="p-2">{{ $i + 1 }}</td>
<td class="p-2">{{ $wali->nama_wali ?? '-' }}</td>
<td class="p-2">{{ $wali->email ?? '-' }}</td>
<td class="p-2 font-medium">{{ $wali->nama_wali ?? '-' }}</td>
<td class="p-2">{{ $wali->no_hp ?? '-' }}</td>
<td class="p-2">{{ $wali->alamat ?? '-' }}</td>
<td class="p-2 text-sm text-gray-600">{{ $wali->alamat ?? '-' }}</td>
<td class="p-2 space-x-2">
<a href="{{ route('wali-murid.edit', $wali->id) }}" class="text-blue-500 hover:underline">Edit</a>
<form action="{{ route('wali-murid.destroy', $wali->id) }}" method="POST" class="inline" onsubmit="return confirm('Yakin hapus data ini?');">
<form action="{{ route('wali-murid.destroy', $wali->id) }}" method="POST" class="inline" onsubmit="return confirm('Yakin hapus?');">
@csrf
@method('DELETE')
<button type="submit" class="text-red-500 hover:underline">Hapus</button>
@ -40,10 +51,10 @@ class="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700 transition">
</tr>
@empty
<tr>
<td colspan="6" class="text-center text-gray-500 py-4">Belum ada data wali murid.</td>
<td colspan="5" class="text-center text-gray-500 py-4">Belum ada data wali murid.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@endsection
@endsection

View File

@ -1,36 +1,29 @@
@extends('layouts.app')
@section('content')
<div class="bg-white shadow-md rounded-lg p-6">
<h2 class="text-xl font-semibold mb-4">Tambah Data Wali Murid</h2>
<div class="bg-white shadow-md rounded-lg p-6 max-w-xl mx-auto">
<h1 class="text-xl font-semibold text-gray-700 mb-4"> Tambah Wali Murid</h1>
<form action="{{ route('wali-murid.store') }}" method="POST" class="space-y-4">
<form action="{{ route('wali.store') }}" method="POST">
@csrf
<div>
<label class="block text-gray-700 font-medium">Nama Wali</label>
<input type="text" name="nama_wali" class="w-full border rounded p-2" required>
<div class="mb-4">
<label class="block text-gray-700">Nama Wali</label>
{{-- PENTING: name="nama_wali", bukan "nama" --}}
<input type="text" name="nama_wali" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300" required>
</div>
<div>
<label class="block text-gray-700 font-medium">Email</label>
<input type="email" name="email" class="w-full border rounded p-2">
<div class="mb-4">
<label class="block text-gray-700">No HP</label>
<input type="text" name="no_hp" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300">
</div>
<div>
<label class="block text-gray-700 font-medium">No HP</label>
<input type="text" name="no_hp" class="w-full border rounded p-2">
<div class="mb-4">
<label class="block text-gray-700">Alamat</label>
<textarea name="alamat" class="w-full border rounded px-3 py-2 focus:ring focus:ring-green-300" rows="3"></textarea>
</div>
<div>
<label class="block text-gray-700 font-medium">Alamat</label>
<textarea name="alamat" rows="3" class="w-full border rounded p-2"></textarea>
</div>
<div class="flex justify-end gap-2">
<a href="{{ route('wali-murid.index') }}" class="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600">Batal</a>
<button type="submit" class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700">Simpan</button>
</div>
<button type="submit" class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600">Simpan</button>
</form>
</div>
@endsection
@endsection

View File

@ -3,45 +3,42 @@
@section('content')
<div class="bg-white shadow-md rounded-lg p-6">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-semibold flex items-center gap-2">
👨‍👩‍👧 Data Wali Murid
</h2>
<a href="{{ route('wali-murid.create') }}" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg">+ Tambah Wali Murid</a>
<h1 class="text-xl font-semibold text-gray-700">👪 Data Wali Murid</h1>
<a href="{{ route('wali.create') }}" class="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700">+ Tambah Wali</a>
</div>
<table class="w-full border-collapse">
<thead class="bg-green-700 text-white">
<tr>
<th class="p-3 text-left">#</th>
<th class="p-3 text-left">Nama Wali</th>
<th class="p-3 text-left">Email</th>
<th class="p-3 text-left">No HP</th>
<th class="p-3 text-left">Alamat</th>
<th class="p-3 text-left">Aksi</th>
<thead>
<tr class="bg-green-600 text-white text-left">
<th class="p-2">No</th>
<th class="p-2">Nama Wali</th>
<th class="p-2">No HP</th>
<th class="p-2">Alamat</th>
<th class="p-2">Aksi</th>
</tr>
</thead>
<tbody>
@forelse ($wali_murids as $wali)
<tr class="border-b hover:bg-gray-100">
<td class="p-3">{{ $loop->iteration }}</td>
<td class="p-3">{{ $wali->nama_wali }}</td>
<td class="p-3">{{ $wali->email }}</td>
<td class="p-3">{{ $wali->no_hp }}</td>
<td class="p-3">{{ $wali->alamat }}</td>
<td class="p-3 flex gap-2">
<a href="{{ route('wali-murid.edit', $wali->id) }}" class="text-blue-600 hover:underline">Edit</a>
<form action="{{ route('wali-murid.destroy', $wali->id) }}" method="POST" onsubmit="return confirm('Yakin ingin menghapus data ini?');">
@csrf
@method('DELETE')
<button type="submit" class="text-red-600 hover:underline">Hapus</button>
</form>
</td>
</tr>
@forelse ($walis as $i => $wali)
<tr class="border-b hover:bg-gray-50">
<td class="p-2">{{ $i + 1 }}</td>
<td class="p-2 font-medium">{{ $wali->nama_wali ?? '-' }}</td>
<td class="p-2">{{ $wali->no_hp ?? '-' }}</td>
<td class="p-2 text-sm text-gray-600">{{ $wali->alamat ?? '-' }}</td>
<td class="p-2 space-x-2">
<a href="{{ route('wali.edit', $wali->id) }}" class="text-blue-500 hover:underline">Edit</a>
<form action="{{ route('wali.destroy', $wali->id) }}" method="POST" class="inline" onsubmit="return confirm('Yakin hapus?');">
@csrf
@method('DELETE')
<button type="submit" class="text-red-500 hover:underline">Hapus</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="6" class="p-3 text-center text-gray-500">Belum ada data wali murid.</td>
</tr>
<tr>
<td colspan="5" class="text-center text-gray-500 py-4">Belum ada data wali murid.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@endsection
@endsection