diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index fdbf565..089cc2c 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -100,7 +100,9 @@ public function sendOtp(Request $request) // Simpan email ke session untuk prefill form login session(['email' => $user->email]); - return back()->with('otp_sent', 'OTP berhasil dikirim!'); + return back() + ->with('otp_sent', 'OTP berhasil dikirim!') + ->with('need_otp', true); // ← tambahkan ini } @@ -108,82 +110,116 @@ public function sendOtp(Request $request) // Dipanggil dari form Langkah 2 di halaman login public function loginOtp(Request $request) { + \Log::info('=== LOGIN OTP CALLED - AuthController ==='); $request->validate([ 'email' => 'required|email', 'password' => 'required', 'otp' => 'nullable|digits:6', ]); - // ✅ FIX: tambah with('guru') agar relasi ter-load - $user = User::with('guru')->where('email', $request->email)->first(); + $user = User::with(['guru', 'siswa'])->where('email', $request->email)->first(); if (!$user) { return back()->with('error', 'Email tidak ditemukan.'); } - // Cek password if (!Hash::check($request->password, $user->password)) { return back()->with('error', 'Password salah.'); } - // ================================================= - // ADMIN → LANGSUNG LOGIN TANPA OTP - // ================================================= + // ADMIN → langsung login tanpa OTP if ($user->role === 'admin') { - Auth::login($user); $request->session()->regenerate(); - return redirect()->route('admin.dashboard'); } - // ================================================= - // GURU / SISWA WAJIB OTP - // ================================================= - if (in_array($user->role, ['guru', 'siswa'])) { + // Cek status nonaktif + if ($user->role === 'guru' && (!$user->guru || $user->guru->status === 'nonaktif')) { + return back()->with('error', 'Akun Anda telah dinonaktifkan.'); + } + if ($user->role === 'siswa' && (!$user->siswa || $user->siswa->status === 'nonaktif')) { + return back()->with('error', 'Akun Anda telah dinonaktifkan.'); + } - // ✅ FIX: cek status nonaktif sebelum proses OTP - if ($user->role === 'guru') { - $user->load('guru'); // reload fresh dari DB - if (!$user->guru || $user->guru->status === 'nonaktif') { - return back()->with('error', 'Akun Anda telah dinonaktifkan. Hubungi administrator.'); - } - } + // ── Cek cookie trusted device (per user per device) ── + $cookieKey = 'trusted_device_' . $user->id; + // SESUDAH +$cookieValue = \Illuminate\Support\Facades\Cookie::get($cookieKey); + $trustedDevices = $user->trusted_devices ?? []; + $isDeviceTrusted = $cookieValue && in_array($cookieValue, $trustedDevices); + +// DEBUG SEMENTARA — hapus setelah fix +\Log::info('COOKIE CHECK', [ + 'cookie_key' => $cookieKey, + 'cookie_value' => $cookieValue, + 'trusted_list' => $trustedDevices, + 'is_trusted' => $isDeviceTrusted, +]); + + // Device BARU → wajib OTP + if (!$isDeviceTrusted) { if (empty($request->otp)) { - return back()->with('error', 'OTP wajib diisi.'); + return back() + ->withInput() + ->with('error', 'Perangkat baru terdeteksi! Silakan minta OTP terlebih dahulu.') + ->with('need_otp', true); } if (!$user->otp) { - return back()->with('error', 'OTP belum diminta.'); + return back()->withInput() + ->with('error', 'OTP belum diminta.') + ->with('need_otp', true); } if ((string)$request->otp !== (string)$user->otp) { - return back()->with('error', 'Kode OTP salah.'); + return back()->withInput() + ->with('error', 'Kode OTP salah.') + ->with('need_otp', true); } if (!$user->otp_expired_at || now()->gt($user->otp_expired_at)) { - return back()->with('error', 'OTP sudah kadaluarsa.'); + return back()->withInput() + ->with('error', 'OTP sudah kadaluarsa.') + ->with('need_otp', true); } - // Login + // Generate token unik untuk device ini + $deviceToken = \Illuminate\Support\Str::random(60); + + // Simpan ke trusted_devices (maks 10) + $trustedDevices[] = $deviceToken; + if (count($trustedDevices) > 10) array_shift($trustedDevices); + + $user->update([ + 'otp' => null, + 'otp_expired_at' => null, + 'trusted_devices' => $trustedDevices, + ]); + Auth::login($user); $request->session()->regenerate(); - // Hapus OTP - $user->update([ - 'otp' => null, - 'otp_expired_at' => null, - ]); + // Simpan cookie selama 365 hari + $cookie = cookie($cookieKey, $deviceToken, 60 * 24 * 365, '/', null, false, true); return match ($user->role) { - 'guru' => redirect()->route('guru.dashboard'), - 'siswa' => redirect()->route('siswa.dashboard'), - default => redirect('/'), + 'guru' => redirect()->route('guru.dashboard')->withCookie($cookie), + 'siswa' => redirect()->route('siswa.dashboard')->withCookie($cookie), + default => redirect('/')->withCookie($cookie), }; } - return back()->with('error', 'Role tidak dikenali.'); + // Device LAMA → langsung login + Auth::login($user); + $request->session()->regenerate(); + + return match ($user->role) { + 'guru' => redirect()->route('guru.dashboard'), + 'siswa' => redirect()->route('siswa.dashboard'), + default => redirect('/'), + }; } diff --git a/app/Http/Controllers/admin/GuruController.php b/app/Http/Controllers/admin/GuruController.php index 598bd92..b7d0c65 100644 --- a/app/Http/Controllers/admin/GuruController.php +++ b/app/Http/Controllers/admin/GuruController.php @@ -33,6 +33,15 @@ public function create() // ================= STORE ================= public function store(Request $request) { + if ($request->has('telepon')) { + $telepon = $request->telepon; + $telepon = ltrim($telepon, '+'); + if (strpos($telepon, '62') === 0) { + $telepon = '0' . substr($telepon, 2); + } + $request->merge(['telepon' => $telepon]); + } + $request->validate([ 'nama' => 'required', 'nip' => 'required|unique:gurus,nip', @@ -42,7 +51,7 @@ public function store(Request $request) 'email' => 'required|email|unique:users,email' ]); - // 🔥 CEK JIKA SUDAH ADA (ANTI DOUBLE INSERT) + // 🔥 CEK JIKA SUDAH ADA (ANTI DOUBLE INSERT) if (Guru::where('nip', $request->nip)->exists()) { return back()->withErrors(['nip' => 'NIP sudah ada'])->withInput(); } @@ -83,6 +92,15 @@ public function edit($id) // ================= UPDATE ================= public function update(Request $request, Guru $guru) { + if ($request->has('telepon')) { + $telepon = $request->telepon; + $telepon = ltrim($telepon, '+'); + if (strpos($telepon, '62') === 0) { + $telepon = '0' . substr($telepon, 2); + } + $request->merge(['telepon' => $telepon]); + } + $request->validate([ 'nama' => 'required', 'nip' => 'required|unique:gurus,nip,' . $guru->id, @@ -94,18 +112,18 @@ public function update(Request $request, Guru $guru) $guru->update([ 'nama' => $request->nama, 'nip' => $request->nip, - 'mapel_id' => $request->mapel_id, // 🔥 INI WAJIB + 'mapel_id' => $request->mapel_id, // 🔥 INI WAJIB 'alamat' => $request->alamat, 'telepon' => $request->telepon, ]); - // 🔥 UPDATE USER (TELEPON JUGA UPDATE) + // 🔥 UPDATE USER (TELEPON JUGA UPDATE) $user = User::where('guru_id', $guru->id)->first(); if ($user) { $user->update([ 'name' => $request->nama, 'mapel_id' => $request->mapel_id, - 'telepon' => $request->telepon // ✅ WAJIB ADA + 'telepon' => $request->telepon // ✅ WAJIB ADA ]); } diff --git a/app/Http/Controllers/admin/JadwalController.php b/app/Http/Controllers/admin/JadwalController.php index d0148dd..f7b0726 100644 --- a/app/Http/Controllers/admin/JadwalController.php +++ b/app/Http/Controllers/admin/JadwalController.php @@ -54,6 +54,11 @@ public function store(Request $request) 'jam_selesai' => 'required', ]); + // ✅ Validasi jam selesai harus lebih besar dari jam mulai + if ($request->jam_selesai <= $request->jam_mulai) { + return back()->withInput()->with('error', 'Jam selesai harus lebih besar dari jam mulai!'); + } + // 🔥 CEK BENTROK KELAS $cekKelas = Jadwal::where('kelas_id', $request->kelas_id) ->where('hari', $request->hari) @@ -120,6 +125,11 @@ public function update(Request $request, $id) 'jam_selesai' => 'required', ]); + // ✅ Validasi jam selesai harus lebih besar dari jam mulai + if ($request->jam_selesai <= $request->jam_mulai) { + return back()->withInput()->with('error', 'Jam selesai harus lebih besar dari jam mulai!'); + } + $jadwal->update([ 'kelas_id' => $request->kelas_id, 'mata_pelajaran_id' => $request->mata_pelajaran_id, diff --git a/app/Http/Controllers/admin/ProfileController.php b/app/Http/Controllers/admin/ProfileController.php index aa5d739..0e9689c 100644 --- a/app/Http/Controllers/admin/ProfileController.php +++ b/app/Http/Controllers/admin/ProfileController.php @@ -13,29 +13,50 @@ public function index() return view('admin.profile.index'); } - public function update(Request $request) - { - $user = Auth::user(); + public function update(Request $request) +{ + $user = Auth::user(); - $request->validate([ - 'name' => 'required', - 'photo' => 'nullable|image|mimes:jpg,jpeg,png|max:2048' - ]); + $rules = [ + 'name' => 'required', + 'photo' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:2048', + ]; - // update nama - $user->name = $request->name; + // Tambahan validasi khusus siswa + if ($user->role == 'siswa') { + $rules['nama_ortu'] = 'required'; + $rules['alamat'] = 'required'; + $rules['telepon'] = 'required'; + } - // upload foto - if ($request->hasFile('photo')) { - $file = $request->file('photo'); - $filename = time() . '.' . $file->getClientOriginalExtension(); - $file->move(public_path('uploads'), $filename); + $request->validate($rules); - $user->photo = $filename; + // Update foto + if ($request->hasFile('photo')) { + $file = $request->file('photo'); + $namaFile = time() . '.' . $file->extension(); + $file->move(public_path('uploads'), $namaFile); + $user->photo = $namaFile; + } + + $user->name = $request->name; + $user->save(); + + // Update tabel siswa jika role siswa + if ($user->role == 'siswa' && $user->siswa) { + $telepon = ltrim($request->telepon, '+'); + if (strpos($telepon, '62') === 0) { + $telepon = '0' . substr($telepon, 2); } - $user->save(); - - return back()->with('success', 'Profil berhasil diupdate'); + $user->siswa->update([ + 'nama' => $request->name, + 'nama_ortu' => $request->nama_ortu, + 'alamat' => $request->alamat, + 'telepon' => $telepon, + ]); } + + return back()->with('success', 'Profile berhasil diupdate'); +} } \ No newline at end of file diff --git a/app/Http/Controllers/admin/SiswaController.php b/app/Http/Controllers/admin/SiswaController.php index 304c7ec..b91eee0 100644 --- a/app/Http/Controllers/admin/SiswaController.php +++ b/app/Http/Controllers/admin/SiswaController.php @@ -41,6 +41,18 @@ public function store(Request $request) \Log::info('STORE DIPANGGIL'); + if ($request->has('telepon')) { + $telepon = $request->telepon; + // Hapus tanda plus jika ada (+62 -> 62) + $telepon = ltrim($telepon, '+'); + // Jika tipenya string diawali dengan 62, ganti jadi 0 + if (strpos($telepon, '62') === 0) { + $telepon = '0' . substr($telepon, 2); + } + // Masukkan kembali nilai yang sudah rapi ke dalam request + $request->merge(['telepon' => $telepon]); + } + $request->validate([ 'nama' => 'required', 'jenis_kelamin' => 'required', @@ -72,10 +84,10 @@ public function store(Request $request) $user = User::create([ 'name' => $request->nama, 'email' => $request->email, - 'password' => Hash::make('12345678'), // 🔥 default + 'password' => Hash::make('12345678'), // 🔥 default 'role' => 'siswa', // atau guru 'siswa_id' => $siswa->id, - 'is_default_password' => true // 🔥 WAJIB + 'is_default_password' => true // 🔥 WAJIB ]); /** @var \App\Models\User $user */ @@ -95,6 +107,19 @@ public function edit(Siswa $siswa) // ================= UPDATE ================= public function update(Request $request, Siswa $siswa) { + + if ($request->has('telepon')) { + $telepon = $request->telepon; + // Hapus tanda plus jika ada (+62 -> 62) + $telepon = ltrim($telepon, '+'); + // Jika tipenya string diawali dengan 62, ganti jadi 0 + if (strpos($telepon, '62') === 0) { + $telepon = '0' . substr($telepon, 2); + } + // Masukkan kembali nilai yang sudah rapi ke dalam request + $request->merge(['telepon' => $telepon]); + } + $request->validate([ 'nama' => 'required', 'jenis_kelamin' => 'required', diff --git a/app/Http/Controllers/auth/OtpController.php b/app/Http/Controllers/auth/OtpController.php index 7560611..5c47f50 100644 --- a/app/Http/Controllers/auth/OtpController.php +++ b/app/Http/Controllers/auth/OtpController.php @@ -11,6 +11,7 @@ class OtpController extends Controller // ================= KIRIM OTP ================= public function sendOtp(Request $request) { + \Log::info('=== LOGIN OTP CALLED - OtpController ==='); $method = $request->input('method', 'email'); if ($method === 'email') { @@ -65,73 +66,124 @@ public function sendOtp(Request $request) // ================= LOGIN DENGAN OTP ================= public function loginOtp(Request $request) - { - $request->validate([ - 'email' => 'required|email', - 'password' => 'required', - 'otp' => 'nullable|digits:6', +{ + \Log::info('=== LOGIN OTP CALLED - OtpController ==='); + + $request->validate([ + 'email' => 'required|email', + 'password' => 'required', + 'otp' => 'nullable|digits:6', + ]); + + $user = User::with(['guru', 'siswa'])->where('email', $request->email)->first(); + + if (!$user) { + return back()->with('error', 'Email tidak ditemukan.'); + } + + if (!\Hash::check($request->password, $user->password)) { + return back()->with('error', 'Password salah.'); + } + + // ADMIN → langsung login tanpa OTP + if ($user->role === 'admin') { + \Auth::login($user); + $request->session()->regenerate(); + return redirect()->route('admin.dashboard'); + } + + // Cek status nonaktif + if ($user->role === 'guru' && (!$user->guru || $user->guru->status === 'nonaktif')) { + return back()->with('error', 'Akun Anda telah dinonaktifkan.'); + } + if ($user->role === 'siswa' && (!$user->siswa || $user->siswa->status === 'nonaktif')) { + return back()->with('error', 'Akun Anda telah dinonaktifkan.'); + } + + // ── Cek cookie trusted device ── + $cookieKey = 'trusted_device_' . $user->id; + $cookieValue = $request->cookie($cookieKey); + $trustedDevices = $user->trusted_devices ?? []; + $isDeviceTrusted = $cookieValue && in_array($cookieValue, $trustedDevices); + + \Log::info('=== DEVICE CHECK ===', [ + 'user_id' => $user->id, + 'cookie_key' => $cookieKey, + 'cookie_value' => $cookieValue, + 'trusted_list' => $trustedDevices, + 'is_trusted' => $isDeviceTrusted, + 'all_cookies' => array_keys($request->cookies->all()), + ]); + + // Device BARU → wajib OTP + if (!$isDeviceTrusted) { + + if (empty($request->otp)) { + return back() + ->withInput() + ->with('error', 'Perangkat baru terdeteksi! Silakan minta OTP terlebih dahulu.') + ->with('need_otp', true); + } + + if (!$user->otp) { + return back()->withInput() + ->with('error', 'OTP belum diminta.') + ->with('need_otp', true); + } + + if ((string)$request->otp !== (string)$user->otp) { + return back()->withInput() + ->with('error', 'Kode OTP salah.') + ->with('need_otp', true); + } + + if (!$user->otp_expired_at || now()->gt($user->otp_expired_at)) { + return back()->withInput() + ->with('error', 'OTP sudah kadaluarsa.') + ->with('need_otp', true); + } + + // Generate token unik untuk device ini + $deviceToken = \Illuminate\Support\Str::random(60); + + // Simpan ke trusted_devices (maks 10) + $trustedDevices[] = $deviceToken; + if (count($trustedDevices) > 10) array_shift($trustedDevices); + + $user->update([ + 'otp' => null, + 'otp_expired_at' => null, + 'trusted_devices' => $trustedDevices, ]); - $user = User::with(['guru', 'siswa'])->where('email', $request->email)->first(); - - if (!$user) { - return back()->with('error', 'User tidak ditemukan'); - } - - if (!\Hash::check($request->password, $user->password)) { - return back()->with('error', 'Password salah'); - } - - // ✅ FIX: cek status nonaktif untuk guru - if ($user->role === 'guru') { - $user->load('guru'); - if (!$user->guru || $user->guru->status === 'nonaktif') { - return back()->with('error', 'Akun Anda telah dinonaktifkan. Hubungi administrator.'); - } - } - - // ✅ FIX BARU: cek status nonaktif untuk siswa - if ($user->role === 'siswa') { - $user->load('siswa'); - if (!$user->siswa || $user->siswa->status === 'nonaktif') { - return back()->with('error', 'Akun Anda telah dinonaktifkan. Hubungi administrator.'); - } - } - - // Guru & Siswa wajib OTP - if (in_array($user->role, ['guru', 'siswa'])) { - - if (!$request->otp) { - return back()->with('error', 'OTP wajib diisi'); - } - - if (!$user->otp) { - return back()->with('error', 'OTP belum diminta'); - } - - if ((string) $request->otp !== (string) $user->otp) { - return back()->with('error', 'OTP salah'); - } - - if (!$user->otp_expired_at || now()->gt($user->otp_expired_at)) { - return back()->with('error', 'OTP sudah kadaluarsa'); - } - } - \Auth::login($user); $request->session()->regenerate(); - if (in_array($user->role, ['guru', 'siswa'])) { - $user->update(['otp' => null, 'otp_expired_at' => null]); - } + // Simpan cookie 365 hari + $cookie = cookie($cookieKey, $deviceToken, 60 * 24 * 365, '/', null, false, true); - session()->forget('email'); + \Log::info('=== DEVICE TRUSTED SAVED ===', [ + 'token' => $deviceToken, + 'cookie_key' => $cookieKey, + ]); return match ($user->role) { - 'admin' => redirect()->route('admin.dashboard'), - 'guru' => redirect()->route('guru.dashboard'), - 'siswa' => redirect()->route('siswa.dashboard'), - default => redirect('/'), + 'guru' => redirect()->route('guru.dashboard')->withCookie($cookie), + 'siswa' => redirect()->route('siswa.dashboard')->withCookie($cookie), + default => redirect('/')->withCookie($cookie), }; } + + // Device LAMA → langsung login + \Log::info('=== DEVICE ALREADY TRUSTED - SKIP OTP ==='); + + \Auth::login($user); + $request->session()->regenerate(); + + return match ($user->role) { + 'guru' => redirect()->route('guru.dashboard'), + 'siswa' => redirect()->route('siswa.dashboard'), + default => redirect('/'), + }; +} } \ No newline at end of file diff --git a/app/Http/Controllers/guru/DashboardController.php b/app/Http/Controllers/guru/DashboardController.php index 883ca24..63f0f76 100644 --- a/app/Http/Controllers/guru/DashboardController.php +++ b/app/Http/Controllers/guru/DashboardController.php @@ -1,6 +1,6 @@ with('success', 'Nilai ' . strtoupper($jenis) . ' berhasil dikirim ke menu nilai!'); } + // ── KIRIM NILAI KE SISWA ───────────────────────────────────────── +public function kirimKeSiswa(Request $request) +{ + $request->validate([ + 'kelas_id' => 'required', + ]); + + $user = auth()->user(); + $mapel_id = $user->mapel_id; + + $nilaiList = Nilai::with('siswa') + ->where('mapel_id', $mapel_id) + ->whereHas('siswa', fn($q) => $q->where('kelas_id', $request->kelas_id)) + ->get(); + + foreach ($nilaiList as $n) { + $n->update(['sudah_kirim' => true]); // ✅ ganti is_published → sudah_kirim + } + + return back()->with('success', 'Nilai berhasil dikirim ke siswa!'); +} + // ── EDIT ───────────────────────────────────────────────────────── public function edit($id) { diff --git a/app/Http/Controllers/guru/TugasController.php b/app/Http/Controllers/guru/TugasController.php index 4084ddc..bb6f7f6 100644 --- a/app/Http/Controllers/guru/TugasController.php +++ b/app/Http/Controllers/guru/TugasController.php @@ -215,4 +215,52 @@ public function nilai(Request $request, $id) return back()->with('success', 'Nilai berhasil disimpan'); } + + public function create() +{ + $guru = auth()->user()->guru; + $kelas = Kelas::all(); + + // Ambil satu mapel pertama yang diajarkan guru ini + $mapel = Jadwal::where('guru_id', $guru->id) + ->join('mata_pelajarans', 'jadwals.mata_pelajaran_id', '=', 'mata_pelajarans.id') + ->select('mata_pelajarans.id', 'mata_pelajarans.nama_mapel') + ->first(); + + return view('guru.tugas.create', compact('kelas', 'guru', 'mapel')); +} + +public function store(Request $request) +{ + $request->validate([ + 'judul' => 'required', + 'kelas_id' => 'required', + 'mapel_id' => 'required', + 'deadline' => 'required', + 'file' => 'nullable|max:10240', + ], [ + 'mapel_id.required' => 'Mata pelajaran belum diset, hubungi admin untuk mengatur jadwal.', + 'file.max' => 'Ukuran file maksimal 10MB.', + ]); + + $guru = auth()->user()->guru; + + $filePath = null; + if ($request->hasFile('file')) { + $filePath = $request->file('file')->store('tugas_file', 'public'); + } + + Tugas::create([ + 'judul' => $request->judul, + 'deskripsi' => $request->deskripsi, + 'kelas_id' => $request->kelas_id, + 'mapel_id' => $request->mapel_id, // ✅ sesuaikan nama kolom + 'guru_id' => $guru->id, + 'deadline' => $request->deadline, + 'file' => $filePath, + ]); + + return redirect()->route('guru.tugas.index') + ->with('success', 'Tugas berhasil dibuat'); +} } \ No newline at end of file diff --git a/app/Http/Middleware/EncryptCookies.php b/app/Http/Middleware/EncryptCookies.php new file mode 100644 index 0000000..e5024a1 --- /dev/null +++ b/app/Http/Middleware/EncryptCookies.php @@ -0,0 +1,15 @@ + 'datetime', 'password' => 'hashed', + 'trusted_devices' => 'array', ]; /* @@ -94,7 +96,7 @@ public function mapel() return $this->belongsTo(MataPelajaran::class, 'mapel_id'); } - + /* |-------------------------------------------------------------------------- @@ -104,20 +106,20 @@ public function mapel() // Ambil nomor WA dengan fallback public function getTeleponLengkap() -{ - if ($this->telepon) { - return $this->telepon; - } + { + if ($this->telepon) { + return $this->telepon; + } - if ($this->guru && $this->guru->telepon) { - return $this->guru->telepon; - } + if ($this->guru && $this->guru->telepon) { + return $this->guru->telepon; + } - // 🔥 fallback tambahan (opsional tapi aman) - if ($this->siswa && $this->siswa->telepon) { - return $this->siswa->telepon; - } + // 🔥 fallback tambahan (opsional tapi aman) + if ($this->siswa && $this->siswa->telepon) { + return $this->siswa->telepon; + } - return null; -} + return null; + } } \ No newline at end of file diff --git a/database/migrations/2026_06_16_223908_add_trusted_devices_to_users_table.php b/database/migrations/2026_06_16_223908_add_trusted_devices_to_users_table.php new file mode 100644 index 0000000..219bdbe --- /dev/null +++ b/database/migrations/2026_06_16_223908_add_trusted_devices_to_users_table.php @@ -0,0 +1,28 @@ +json('trusted_devices')->nullable()->after('otp_expired_at'); + }); +} + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + // + }); + } +}; diff --git a/public/uploads/1779500210.png b/public/uploads/1779500210.png new file mode 100644 index 0000000..5651522 Binary files /dev/null and b/public/uploads/1779500210.png differ diff --git a/public/uploads/1781061804.png b/public/uploads/1781061804.png new file mode 100644 index 0000000..c773722 Binary files /dev/null and b/public/uploads/1781061804.png differ diff --git a/public/uploads/1781062405.png b/public/uploads/1781062405.png new file mode 100644 index 0000000..5fa8bc0 Binary files /dev/null and b/public/uploads/1781062405.png differ diff --git a/resources/views/admin/jadwal/create.blade.php b/resources/views/admin/jadwal/create.blade.php index c092cff..b691427 100644 --- a/resources/views/admin/jadwal/create.blade.php +++ b/resources/views/admin/jadwal/create.blade.php @@ -150,17 +150,47 @@ - {{-- JAM --}} -