login siswa update

This commit is contained in:
RetasyaSalsabila 2026-02-23 11:16:23 +07:00
parent a162972d20
commit 6cb4a1bd64
9 changed files with 453 additions and 65 deletions

View File

@ -71,9 +71,9 @@ public function store(Request $request)
->with('success', 'Data siswa berhasil ditambahkan!'); ->with('success', 'Data siswa berhasil ditambahkan!');
} }
public function update(Request $request, $nisn) public function update(Request $request, $id)
{ {
$siswa = Siswa::findOrFail($nisn); $siswa = Siswa::findOrFail($id);
$validated = $request->validate([ $validated = $request->validate([
'nama' => 'required|string|max:100', 'nama' => 'required|string|max:100',
@ -105,9 +105,9 @@ public function update(Request $request, $nisn)
->with('success', 'Data siswa berhasil diupdate!'); ->with('success', 'Data siswa berhasil diupdate!');
} }
public function destroy($nisn) public function destroy($id)
{ {
$siswa = Siswa::findOrFail($nisn); $siswa = Siswa::findOrFail($id);
$siswa->delete(); $siswa->delete();
return redirect()->route('admin.siswa.index') return redirect()->route('admin.siswa.index')

View File

@ -0,0 +1,49 @@
<?php
namespace App\Http\Controllers\Siswa;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
public function showLoginForm()
{
// Kalau sudah login, langsung redirect ke dashboard
if (Auth::guard('siswa')->check()) {
return redirect()->route('siswa.dashboard');
}
return view('auth.login-siswa');
}
public function login(Request $request)
{
$request->validate([
'nisn' => 'required|string',
'password' => 'required|string',
], [
'nisn.required' => 'NISN wajib diisi.',
'password.required' => 'Password wajib diisi.',
]);
$credentials = $request->only('nisn', 'password');
if (Auth::guard('siswa')->attempt($credentials, $request->boolean('remember'))) {
$request->session()->regenerate();
return redirect()->route('siswa.dashboard');
}
return back()->withErrors([
'nisn' => 'NISN atau password salah.',
])->withInput($request->only('nisn'));
}
public function logout(Request $request)
{
Auth::guard('siswa')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->route('siswa.login');
}
}

View File

@ -3,18 +3,15 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Auth\User as Authenticatable;
class Siswa extends Model class Siswa extends Authenticatable
{ {
use HasFactory; use HasFactory;
protected $table = 'siswas'; protected $table = 'siswas';
protected $primaryKey = 'id_siswa'; protected $primaryKey = 'id_siswa';
public $incrementing = true; public $incrementing = true;
protected $keyType = 'int'; protected $keyType = 'int';
protected $fillable = [ protected $fillable = [
@ -28,11 +25,31 @@ class Siswa extends Model
protected $hidden = [ protected $hidden = [
'password', 'password',
'remember_token',
]; ];
// Relasi ke Kelas
public function kelas() public function kelas()
{ {
return $this->belongsTo(Kelas::class, 'id_kelas', 'id_kelas'); return $this->belongsTo(Kelas::class, 'id_kelas', 'id_kelas');
} }
public function pengumpulanTugas()
{
return $this->hasMany(PengumpulanTugas::class, 'id_siswa', 'id_siswa');
}
public function badges()
{
return $this->hasMany(SiswaBadge::class, 'id_siswa', 'id_siswa');
}
public function leaderboards()
{
return $this->hasMany(Leaderboard::class, 'id_siswa', 'id_siswa');
}
public function pesertaChallenges()
{
return $this->hasMany(PesertaChallenge::class, 'id_siswa', 'id_siswa');
}
} }

View File

@ -8,5 +8,6 @@
<p class="mb-4">Ini halaman landing sederhana. Silakan pilih login sesuai role kamu.</p> <p class="mb-4">Ini halaman landing sederhana. Silakan pilih login sesuai role kamu.</p>
<a href="{{ route('admin.login') }}" class="btn btn-primary">Login Admin</a> <a href="{{ route('admin.login') }}" class="btn btn-primary">Login Admin</a>
<a href="{{ route('guru.login') }}" class="btn btn-primary">Login Guru</a> <a href="{{ route('guru.login') }}" class="btn btn-primary">Login Guru</a>
<a href="{{ route('siswa.login') }}" class="btn btn-primary">Login Siswa</a>
</div> </div>
@endsection @endsection

View File

@ -3,49 +3,76 @@
@section('title', 'Login Siswa') @section('title', 'Login Siswa')
@section('content') @section('content')
<div class="card p-4 shadow" style="width: 400px;"> <link rel="stylesheet" href="{{ asset('css/login-siswa.css') }}">
<h4 class="text-center mb-4 fw-bold text-primary">Login Siswa</h4>
{{-- Tombol Back ke Landing Page --}} <section id="signin" class="signin-section">
<a href="{{ url('/') }}" class="btn btn-outline-secondary mb-3"> <div class="signin-container">
Kembali ke Landing Page <h1 class="signin-title">SIGN IN SISWA</h1>
</a>
{{-- Toast Notifikasi Error --}}
<form method="POST" action="{{ route('login.siswa') }}"> @if ($errors->any())
@csrf <div id="toast-error" class="toast-error">
<div class="mb-3"> {{ $errors->first() }}
<label class="form-label">NISN</label>
<input type="text" name="nisn" class="form-control" required>
</div>
<div class="mb-3 position-relative">
<label class="form-label">Password</label>
<div class="input-group">
<input type="password" name="password" id="password" class="form-control" required>
<button type="button" class="btn btn-outline-secondary" id="togglePassword">
👁️
</button>
</div> </div>
</div> @endif
{{-- Remember Me --}} <form method="POST" action="{{ route('siswa.login.submit') }}">
<div class="form-check mb-3"> @csrf
<input class="form-check-input" type="checkbox" name="remember" id="remember"> <div class="form-card">
<label class="form-check-label" for="remember">
Remember Me
</label>
</div>
<button type="submit" class="btn btn-primary w-100">Masuk</button> {{-- NISN --}}
</form> <div class="input-group">
</div> <img src="{{ asset('icons/username.svg') }}" alt="NISN icon" class="input-icon">
<input type="text" name="nisn" class="form-input" placeholder="NISN" required
value="{{ old('nisn') }}">
</div>
{{-- Password --}}
<div class="input-group password-wrapper">
<img src="{{ asset('icons/password.svg') }}" alt="Password icon" class="input-icon">
<input type="password" name="password" class="form-input password-input" placeholder="Password" required>
<button type="button" class="toggle-password" aria-label="Toggle password visibility">
<img src="{{ asset('icons/show.svg') }}" alt="Show password" class="eye-icon">
</button>
</div>
{{-- Remember Me --}}
<div class="remember-wrapper">
<label class="remember-label">
<input type="checkbox" name="remember" {{ old('remember') ? 'checked' : '' }}>
<span>Remember me</span>
</label>
</div>
</div>
<button type="submit" class="submit-btn">SIGN IN</button>
</form>
<a href="{{ route('landing-page') }}" class="back-link"> Kembali ke Landing Page</a>
</div>
</section>
{{-- Script show/hide password --}}
<script> <script>
document.getElementById('togglePassword').addEventListener('click', function() { document.addEventListener('DOMContentLoaded', function () {
const password = document.getElementById('password'); const toggleBtn = document.querySelector('.toggle-password');
const type = password.getAttribute('type') === 'password' ? 'text' : 'password'; const passwordInput = document.querySelector('.password-input');
password.setAttribute('type', type); const eyeIcon = toggleBtn.querySelector('img');
this.textContent = type === 'password' ? '👁️' : '🙈';
}); toggleBtn.addEventListener('click', () => {
const isVisible = passwordInput.type === 'text';
passwordInput.type = isVisible ? 'password' : 'text';
eyeIcon.src = isVisible
? "{{ asset('icons/show.svg') }}"
: "{{ asset('icons/hide.svg') }}";
eyeIcon.alt = isVisible ? "Show password" : "Hide password";
});
const toast = document.getElementById('toast-error');
if (toast) {
setTimeout(() => toast.remove(), 4000);
}
});
</script> </script>
@endsection @endsection

View File

@ -0,0 +1,75 @@
@extends('siswa.layouts.app')
@section('title', 'Dashboard Siswa')
@section('content')
<div class="container-fluid px-0">
<h4 class="fw-bold text-primary mb-4">Dashboard</h4>
<!-- STATS CARDS -->
<div class="row g-3 mb-4">
<div class="col-md-4">
<div class="card border-0 shadow-sm rounded-4 p-3">
<div class="d-flex align-items-center gap-3">
<div style="background:#e6f0ff; border-radius:12px; padding:12px;">
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" width="24" alt="">
</div>
<div>
<div class="text-muted small">Tugas Aktif</div>
<div class="fw-bold fs-5">0</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-0 shadow-sm rounded-4 p-3">
<div class="d-flex align-items-center gap-3">
<div style="background:#e6f0ff; border-radius:12px; padding:12px;">
<img src="{{ asset('images/icon/sidebar/challenge.png') }}" width="24" alt="">
</div>
<div>
<div class="text-muted small">Challenge Selesai</div>
<div class="fw-bold fs-5">0</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-0 shadow-sm rounded-4 p-3">
<div class="d-flex align-items-center gap-3">
<div style="background:#e6f0ff; border-radius:12px; padding:12px;">
<img src="{{ asset('images/icon/sidebar/lb.png') }}" width="24" alt="">
</div>
<div>
<div class="text-muted small">Total EXP</div>
<div class="fw-bold fs-5">0</div>
</div>
</div>
</div>
</div>
</div>
<!-- INFO SISWA -->
<div class="card border-0 shadow-sm rounded-4 p-4">
<h6 class="fw-bold mb-3">Informasi Akun</h6>
<table class="table table-borderless mb-0">
<tr>
<td class="text-muted" width="150">Nama</td>
<td>: {{ Auth::guard('siswa')->user()->nama }}</td>
</tr>
<tr>
<td class="text-muted">NISN</td>
<td>: {{ Auth::guard('siswa')->user()->nisn }}</td>
</tr>
<tr>
<td class="text-muted">Kelas</td>
<td>: {{ Auth::guard('siswa')->user()->kelas->nama_kelas ?? '-' }}</td>
</tr>
</table>
</div>
</div>
@endsection

View File

@ -0,0 +1,219 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@yield('title', 'Siswa Panel')</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
font-family: 'Poppins', sans-serif;
background-color: #f8f9fa;
margin: 0;
}
.siswa-wrapper {
display: flex;
min-height: 100vh;
}
/* SIDEBAR */
.sidebar {
width: 260px;
background: #ffffff;
border-right: 2px solid #e6f0ff;
padding: 30px 20px;
display: flex;
flex-direction: column;
}
.sidebar-logo {
text-align: center;
margin-bottom: 40px;
}
.sidebar-logo img {
width: 90px;
}
.sidebar-menu {
display: flex;
flex-direction: column;
}
.sidebar-link {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 18px;
margin-bottom: 12px;
border-radius: 12px;
color: #64748b;
text-decoration: none;
font-weight: 500;
transition: all 0.2s ease;
}
.sidebar-link:hover {
background: #e6f0ff;
color: #1d4ed8;
}
.sidebar-link.active {
background: #e6f0ff;
color: #1d4ed8;
}
.sidebar-icon {
width: 20px;
height: 20px;
flex-shrink: 0;
}
.sidebar-logout {
margin-top: auto;
}
.sidebar-logout button {
width: 100%;
border: none;
background: transparent;
color: #ef4444;
font-weight: 600;
padding: 10px;
text-align: left;
cursor: pointer;
}
/* MAIN */
.main {
flex: 1;
background: #f5f9ff;
display: flex;
flex-direction: column;
}
/* TOPBAR */
.topbar {
background: #2b8ef3;
margin: 20px;
padding: 16px 24px;
border-radius: 16px;
color: white;
display: flex;
justify-content: space-between;
align-items: center;
}
.topbar-left {
font-weight: 600;
font-size: 16px;
}
.topbar-right {
display: flex;
align-items: center;
gap: 16px;
}
.topbar-icon {
width: 24px;
height: 24px;
cursor: pointer;
}
/* CONTENT */
.content {
padding: 20px 30px;
flex: 1;
}
</style>
@stack('styles')
</head>
<body>
<div class="siswa-wrapper">
<!-- SIDEBAR -->
<aside class="sidebar">
<div class="sidebar-logo">
<img src="{{ asset('images/logo/logosmk.png') }}" alt="Logo SMK">
</div>
<nav class="sidebar-menu">
<a href="{{ route('siswa.dashboard') }}"
class="sidebar-link {{ request()->routeIs('siswa.dashboard') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/home.png') }}" class="sidebar-icon" alt="">
<span>Dashboard</span>
</a>
<a href="#"
class="sidebar-link {{ request()->routeIs('siswa.materi*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt="">
<span>Materi</span>
</a>
<a href="#"
class="sidebar-link {{ request()->routeIs('siswa.tugas*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon" alt="">
<span>Tugas</span>
</a>
<a href="#"
class="sidebar-link {{ request()->routeIs('siswa.challenge*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/challenge.png') }}" class="sidebar-icon" alt="">
<span>Challenge</span>
</a>
<a href="#"
class="sidebar-link {{ request()->routeIs('siswa.leaderboard*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/lb.png') }}" class="sidebar-icon" alt="">
<span>Leaderboard</span>
</a>
<a href="#"
class="sidebar-link {{ request()->routeIs('siswa.profil*') ? 'active' : '' }}">
<img src="{{ asset('images/icon/sidebar/profil.png') }}" class="sidebar-icon" alt="">
<span>Profil</span>
</a>
</nav>
<form action="{{ route('siswa.logout') }}" method="POST" class="sidebar-logout">
@csrf
<button type="submit">Logout</button>
</form>
</aside>
<!-- MAIN -->
<div class="main">
<!-- TOPBAR -->
<header class="topbar">
<div class="topbar-left">
👋 Hai, {{ Auth::guard('siswa')->user()->nama ?? 'Siswa' }}
</div>
<div class="topbar-right">
<img src="{{ asset('images/icon/sidebar/notif.png') }}" class="topbar-icon" alt="Notification">
<img src="{{ asset('images/icon/sidebar/profil.png') }}" class="topbar-icon" alt="Profile">
</div>
</header>
<!-- CONTENT -->
<main class="content">
@yield('content')
</main>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
@stack('scripts')
</body>
</html>

View File

@ -25,6 +25,8 @@
use App\Http\Controllers\Guru\MapelController as GuruMapelController; use App\Http\Controllers\Guru\MapelController as GuruMapelController;
use App\Http\Controllers\Guru\LeaderboardController as GuruLeaderboardController; use App\Http\Controllers\Guru\LeaderboardController as GuruLeaderboardController;
//SISWA CONTROLLERS
use App\Http\Controllers\Siswa\LoginController as SiswaLoginController;
// ==================== // ====================
// LANDING PAGE // LANDING PAGE
@ -48,9 +50,8 @@
->name('guru.login'); ->name('guru.login');
// LOGIN SISWA // LOGIN SISWA
Route::get('/siswa/login', function () { Route::get('/siswa/login', [SiswaLoginController::class, 'showLoginForm'])
return view('auth.login-siswa'); ->name('siswa.login');
})->name('siswa.login');
// ======================================================= // =======================================================
@ -66,15 +67,8 @@
->name('guru.login.submit'); ->name('guru.login.submit');
// SISWA LOGIN PROCESS // SISWA LOGIN PROCESS
Route::post('/siswa/login', function (Request $request) { Route::post('/siswa/login', [SiswaLoginController::class, 'login'])
$credentials = $request->only('nisn', 'password'); ->name('siswa.login.submit');
if (Auth::guard('siswa')->attempt($credentials)) {
return redirect()->route('siswa.dashboard');
}
return back()->withErrors(['nisn' => 'NISN atau password salah']);
})->name('siswa.login.submit');
// ======================================================= // =======================================================
@ -151,8 +145,14 @@
// ======================================================= // =======================================================
// SISWA AREA // SISWA AREA
// ======================================================= // =======================================================
Route::middleware(['auth:siswa'])->group(function () {
Route::get('/siswa/dashboard', function () { Route::middleware(['auth:siswa'])->prefix('siswa')->name('siswa.')->group(function () {
Route::get('/dashboard', function () {
return view('siswa.dashboard'); return view('siswa.dashboard');
})->name('siswa.dashboard'); })->name('dashboard');
});
// LOGOUT SISWA
Route::post('/logout', [SiswaLoginController::class, 'logout'])->name('logout');
});