profile 3 user
This commit is contained in:
parent
3e4c585230
commit
7f81522b85
|
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use App\Models\Admin;
|
||||||
|
|
||||||
|
class ProfileController extends Controller
|
||||||
|
{
|
||||||
|
public function edit()
|
||||||
|
{
|
||||||
|
$admin = Auth::guard('admin')->user();
|
||||||
|
return view('admin.profile.edit', compact('admin'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request)
|
||||||
|
{
|
||||||
|
$admin = Auth::guard('admin')->user();
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'username' => 'required|string|max:100|unique:admins,username,' . $admin->id_admin . ',id_admin',
|
||||||
|
'password' => 'nullable|min:6|confirmed',
|
||||||
|
'password_confirmation' => 'nullable',
|
||||||
|
'foto_profil' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:2048',
|
||||||
|
], [
|
||||||
|
'username.required' => 'Username wajib diisi.',
|
||||||
|
'username.unique' => 'Username sudah digunakan.',
|
||||||
|
'password.min' => 'Password minimal 6 karakter.',
|
||||||
|
'password.confirmed' => 'Konfirmasi password tidak cocok.',
|
||||||
|
'foto_profil.image' => 'File harus berupa gambar.',
|
||||||
|
'foto_profil.max' => 'Ukuran foto maksimal 2MB.',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = ['username' => $request->username];
|
||||||
|
|
||||||
|
if ($request->filled('password')) {
|
||||||
|
$data['password'] = Hash::make($request->password);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->hasFile('foto_profil')) {
|
||||||
|
if ($admin->foto_profil && Storage::disk('public')->exists($admin->foto_profil)) {
|
||||||
|
Storage::disk('public')->delete($admin->foto_profil);
|
||||||
|
}
|
||||||
|
$path = $request->file('foto_profil')->store('foto_profil/admin', 'public');
|
||||||
|
$data['foto_profil'] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
$admin->update($data);
|
||||||
|
|
||||||
|
return redirect()->route('admin.profile.edit')
|
||||||
|
->with('success', 'Profil berhasil diperbarui!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers\Guru;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
|
|
||||||
class ProfilController extends Controller
|
|
||||||
{
|
|
||||||
public function show()
|
|
||||||
{
|
|
||||||
$guru = Auth::guard('guru')->user();
|
|
||||||
return view('guru.profil.show', compact('guru'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update(Request $request)
|
|
||||||
{
|
|
||||||
$guru = Auth::guard('guru')->user();
|
|
||||||
|
|
||||||
$validated = $request->validate([
|
|
||||||
'nama' => 'required|string|max:100',
|
|
||||||
'password' => 'nullable|string|min:6|confirmed',
|
|
||||||
], [
|
|
||||||
'nama.required' => 'Nama wajib diisi',
|
|
||||||
'password.min' => 'Password minimal 6 karakter',
|
|
||||||
'password.confirmed' => 'Konfirmasi password tidak cocok',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$guru->nama = $validated['nama'];
|
|
||||||
|
|
||||||
if ($request->filled('password')) {
|
|
||||||
$guru->password = Hash::make($validated['password']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$guru->save();
|
|
||||||
|
|
||||||
return redirect()->route('guru.profil.show')
|
|
||||||
->with('success', 'Profil berhasil diupdate!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Guru;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class ProfileController extends Controller
|
||||||
|
{
|
||||||
|
public function edit()
|
||||||
|
{
|
||||||
|
$guru = Auth::guard('guru')->user();
|
||||||
|
return view('guru.profile.edit', compact('guru'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request)
|
||||||
|
{
|
||||||
|
$guru = Auth::guard('guru')->user();
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'password' => 'nullable|min:6|confirmed',
|
||||||
|
'password_confirmation' => 'nullable',
|
||||||
|
'foto_profil' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:2048',
|
||||||
|
], [
|
||||||
|
'password.min' => 'Password minimal 6 karakter.',
|
||||||
|
'password.confirmed' => 'Konfirmasi password tidak cocok.',
|
||||||
|
'foto_profil.image' => 'File harus berupa gambar.',
|
||||||
|
'foto_profil.max' => 'Ukuran foto maksimal 2MB.',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
if ($request->filled('password')) {
|
||||||
|
$data['password'] = Hash::make($request->password);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->hasFile('foto_profil')) {
|
||||||
|
if ($guru->foto_profil && Storage::disk('public')->exists($guru->foto_profil)) {
|
||||||
|
Storage::disk('public')->delete($guru->foto_profil);
|
||||||
|
}
|
||||||
|
$path = $request->file('foto_profil')->store('foto_profil/guru', 'public');
|
||||||
|
$data['foto_profil'] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($data)) {
|
||||||
|
$guru->update($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('guru.profile.edit')
|
||||||
|
->with('success', 'Profil berhasil diperbarui!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Http\Requests\ProfileUpdateRequest;
|
|
||||||
use Illuminate\Http\RedirectResponse;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\Redirect;
|
|
||||||
use Illuminate\View\View;
|
|
||||||
|
|
||||||
class ProfileController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Display the user's profile form.
|
|
||||||
*/
|
|
||||||
public function edit(Request $request): View
|
|
||||||
{
|
|
||||||
return view('profile.edit', [
|
|
||||||
'user' => $request->user(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the user's profile information.
|
|
||||||
*/
|
|
||||||
public function update(ProfileUpdateRequest $request): RedirectResponse
|
|
||||||
{
|
|
||||||
$request->user()->fill($request->validated());
|
|
||||||
|
|
||||||
if ($request->user()->isDirty('email')) {
|
|
||||||
$request->user()->email_verified_at = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$request->user()->save();
|
|
||||||
|
|
||||||
return Redirect::route('profile.edit')->with('status', 'profile-updated');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the user's account.
|
|
||||||
*/
|
|
||||||
public function destroy(Request $request): RedirectResponse
|
|
||||||
{
|
|
||||||
$request->validateWithBag('userDeletion', [
|
|
||||||
'password' => ['required', 'current_password'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$user = $request->user();
|
|
||||||
|
|
||||||
Auth::logout();
|
|
||||||
|
|
||||||
$user->delete();
|
|
||||||
|
|
||||||
$request->session()->invalidate();
|
|
||||||
$request->session()->regenerateToken();
|
|
||||||
|
|
||||||
return Redirect::to('/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Siswa;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class ProfileController extends Controller
|
||||||
|
{
|
||||||
|
public function edit()
|
||||||
|
{
|
||||||
|
$siswa = Auth::guard('siswa')->user();
|
||||||
|
return view('siswa.profile.edit', compact('siswa'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request)
|
||||||
|
{
|
||||||
|
$siswa = Auth::guard('siswa')->user();
|
||||||
|
|
||||||
|
$request->validate([
|
||||||
|
'password' => 'nullable|min:6|confirmed',
|
||||||
|
'password_confirmation' => 'nullable',
|
||||||
|
'foto_profil' => 'nullable|image|mimes:jpg,jpeg,png,webp|max:2048',
|
||||||
|
], [
|
||||||
|
'password.min' => 'Password minimal 6 karakter.',
|
||||||
|
'password.confirmed' => 'Konfirmasi password tidak cocok.',
|
||||||
|
'foto_profil.image' => 'File harus berupa gambar.',
|
||||||
|
'foto_profil.max' => 'Ukuran foto maksimal 2MB.',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
// Update password
|
||||||
|
if ($request->filled('password')) {
|
||||||
|
$data['password'] = Hash::make($request->password);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update foto profil
|
||||||
|
if ($request->hasFile('foto_profil')) {
|
||||||
|
// Hapus foto lama jika ada
|
||||||
|
if ($siswa->foto_profil && Storage::disk('public')->exists($siswa->foto_profil)) {
|
||||||
|
Storage::disk('public')->delete($siswa->foto_profil);
|
||||||
|
}
|
||||||
|
$path = $request->file('foto_profil')->store('foto_profil/siswa', 'public');
|
||||||
|
$data['foto_profil'] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($data)) {
|
||||||
|
$siswa->update($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('siswa.profile.edit')
|
||||||
|
->with('success', 'Profil berhasil diperbarui!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,7 +19,8 @@ class Admin extends Authenticatable
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'username',
|
'username',
|
||||||
'password'
|
'password',
|
||||||
|
'foto_profil'
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ class Guru extends Authenticatable
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'nip',
|
'nip',
|
||||||
'nama',
|
'nama',
|
||||||
'password'
|
'password',
|
||||||
|
'foto_profil'
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ class Siswa extends Authenticatable
|
||||||
'tanggal_lahir',
|
'tanggal_lahir',
|
||||||
'id_kelas',
|
'id_kelas',
|
||||||
'password',
|
'password',
|
||||||
|
'foto_profil'
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
if (!Schema::hasColumn('siswas', 'foto_profil')) {
|
||||||
|
Schema::table('siswas', function (Blueprint $table) {
|
||||||
|
$table->string('foto_profil')->nullable()->after('password');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Schema::hasColumn('gurus', 'foto_profil')) {
|
||||||
|
Schema::table('gurus', function (Blueprint $table) {
|
||||||
|
$table->string('foto_profil')->nullable()->after('password');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Schema::hasColumn('admins', 'foto_profil')) {
|
||||||
|
Schema::table('admins', function (Blueprint $table) {
|
||||||
|
$table->string('foto_profil')->nullable()->after('password');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('siswas', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('foto_profil');
|
||||||
|
});
|
||||||
|
Schema::table('gurus', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('foto_profil');
|
||||||
|
});
|
||||||
|
Schema::table('admins', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('foto_profil');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -9,92 +9,42 @@
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body { font-family: 'Poppins', sans-serif; background-color: #f8f9fa; margin: 0; }
|
||||||
font-family: 'Poppins', sans-serif;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-wrapper { display: flex; min-height: 100vh; }
|
.admin-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; }
|
||||||
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 { text-align: center; margin-bottom: 40px; }
|
||||||
.sidebar-logo img { width: 90px; }
|
.sidebar-logo img { width: 90px; }
|
||||||
|
|
||||||
.sidebar-menu { display: flex; flex-direction: column; }
|
.sidebar-menu { display: flex; flex-direction: column; }
|
||||||
|
|
||||||
.sidebar-link {
|
.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; }
|
||||||
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:hover { background: #e6f0ff; color: #1d4ed8; }
|
||||||
.sidebar-link.active { background: #e6f0ff; color: #1d4ed8; }
|
.sidebar-link.active { background: #e6f0ff; color: #1d4ed8; }
|
||||||
|
|
||||||
.sidebar-icon { width: 20px; height: 20px; flex-shrink: 0; }
|
.sidebar-icon { width: 20px; height: 20px; flex-shrink: 0; }
|
||||||
|
|
||||||
.sidebar-section {
|
.sidebar-section { font-size: 10px; font-weight: 700; color: #94a3b8; letter-spacing: 1px; text-transform: uppercase; padding: 4px 18px; margin-bottom: 6px; margin-top: 6px; }
|
||||||
font-size: 10px;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #94a3b8;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
padding: 4px 18px;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
margin-top: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-logout { margin-top: auto; }
|
.sidebar-logout { margin-top: auto; }
|
||||||
|
.sidebar-logout button { width: 100%; border: none; background: transparent; color: #ef4444; font-weight: 600; padding: 10px; text-align: left; }
|
||||||
.sidebar-logout button {
|
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
color: #ef4444;
|
|
||||||
font-weight: 600;
|
|
||||||
padding: 10px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main { flex: 1; background: #f5f9ff; display: flex; flex-direction: column; }
|
.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; }
|
||||||
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-left { font-weight: 600; font-size: 16px; }
|
||||||
.topbar-right { display: flex; align-items: center; gap: 16px; }
|
.topbar-right { display: flex; align-items: center; gap: 14px; }
|
||||||
.topbar-icon { width: 24px; height: 24px; cursor: pointer; }
|
.topbar-icon { width: 24px; height: 24px; cursor: pointer; }
|
||||||
|
|
||||||
|
.topbar-avatar { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; border: 2px solid rgba(255,255,255,0.5); cursor: pointer; transition: border-color 0.2s; display: block; }
|
||||||
|
.topbar-avatar:hover { border-color: white; }
|
||||||
|
|
||||||
|
.topbar-avatar-icon { width: 36px; height: 36px; border-radius: 50%; background: rgba(255,255,255,0.2); border: 2px solid rgba(255,255,255,0.4); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background 0.2s; flex-shrink: 0; text-decoration: none; }
|
||||||
|
.topbar-avatar-icon:hover { background: rgba(255,255,255,0.3); }
|
||||||
|
.topbar-avatar-icon svg { width: 20px; height: 20px; stroke: white; }
|
||||||
|
|
||||||
.content { padding: 20px 30px; flex: 1; }
|
.content { padding: 20px 30px; flex: 1; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@stack('styles')
|
@stack('styles')
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="admin-wrapper">
|
<div class="admin-wrapper">
|
||||||
|
|
||||||
|
|
@ -104,67 +54,39 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="sidebar-menu">
|
<nav class="sidebar-menu">
|
||||||
|
<a href="{{ route('admin.dashboard') }}" class="sidebar-link {{ request()->routeIs('admin.dashboard') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.dashboard') }}"
|
<img src="{{ asset('images/icon/sidebar/home.png') }}" class="sidebar-icon" alt=""><span>Dashboard</span>
|
||||||
class="sidebar-link {{ request()->routeIs('admin.dashboard') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/home.png') }}" class="sidebar-icon" alt="">
|
|
||||||
<span>Dashboard</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="sidebar-section">Data Master</div>
|
<div class="sidebar-section">Data Master</div>
|
||||||
|
<a href="{{ route('admin.guru.index') }}" class="sidebar-link {{ request()->routeIs('admin.guru.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.guru.index') }}"
|
<img src="{{ asset('images/icon/sidebar/guru.png') }}" class="sidebar-icon" alt=""><span>Daftar Guru</span>
|
||||||
class="sidebar-link {{ request()->routeIs('admin.guru.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/guru.png') }}" class="sidebar-icon" alt="">
|
|
||||||
<span>Daftar Guru</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ route('admin.kelas.index') }}" class="sidebar-link {{ request()->routeIs('admin.kelas.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.kelas.index') }}"
|
<img src="{{ asset('images/icon/sidebar/kelas.png') }}" class="sidebar-icon" alt=""><span>Daftar Kelas</span>
|
||||||
class="sidebar-link {{ request()->routeIs('admin.kelas.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/kelas.png') }}" class="sidebar-icon" alt="">
|
|
||||||
<span>Daftar Kelas</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ route('admin.siswa.index') }}" class="sidebar-link {{ request()->routeIs('admin.siswa.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.siswa.index') }}"
|
<img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon" alt=""><span>Daftar Siswa</span>
|
||||||
class="sidebar-link {{ request()->routeIs('admin.siswa.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon" alt="">
|
|
||||||
<span>Daftar Siswa</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ route('admin.mapel.index') }}" class="sidebar-link {{ request()->routeIs('admin.mapel.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.mapel.index') }}"
|
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt=""><span>Mata Pelajaran</span>
|
||||||
class="sidebar-link {{ request()->routeIs('admin.mapel.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt="">
|
|
||||||
<span>Mata Pelajaran</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="sidebar-section">Konten Guru</div>
|
<div class="sidebar-section">Konten Guru</div>
|
||||||
|
<a href="{{ route('admin.materi.history') }}" class="sidebar-link {{ request()->routeIs('admin.materi.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.materi.history') }}"
|
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt=""><span>History Materi</span>
|
||||||
class="sidebar-link {{ request()->routeIs('admin.materi.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt="">
|
|
||||||
<span>History Materi</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ route('admin.tugas.history') }}" class="sidebar-link {{ request()->routeIs('admin.tugas.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.tugas.history') }}"
|
<img src="{{ asset('images/icon/sidebar/guru.png') }}" class="sidebar-icon" alt=""><span>History Tugas</span>
|
||||||
class="sidebar-link {{ request()->routeIs('admin.tugas.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/guru.png') }}" class="sidebar-icon" alt="">
|
|
||||||
<span>History Tugas</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="sidebar-section">Gamifikasi</div>
|
<div class="sidebar-section">Gamifikasi</div>
|
||||||
|
<a href="{{ route('admin.challenge.index') }}" class="sidebar-link {{ request()->routeIs('admin.challenge.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.challenge.index') }}"
|
<img src="{{ asset('images/icon/sidebar/challenge.png') }}" class="sidebar-icon" alt=""><span>Challenge</span>
|
||||||
class="sidebar-link {{ request()->routeIs('admin.challenge.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/challenge.png') }}" class="sidebar-icon" alt="">
|
|
||||||
<span>Challenge</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ route('admin.leaderboard.index') }}" class="sidebar-link {{ request()->routeIs('admin.leaderboard.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('admin.leaderboard.index') }}"
|
<img src="{{ asset('images/icon/sidebar/lb.png') }}" class="sidebar-icon" alt=""><span>Leaderboard</span>
|
||||||
class="sidebar-link {{ request()->routeIs('admin.leaderboard.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/lb.png') }}" class="sidebar-icon" alt="">
|
|
||||||
<span>Leaderboard</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<form action="{{ route('admin.logout') }}" method="POST" class="sidebar-logout">
|
<form action="{{ route('admin.logout') }}" method="POST" class="sidebar-logout">
|
||||||
|
|
@ -180,7 +102,19 @@ class="sidebar-link {{ request()->routeIs('admin.leaderboard.*') ? 'active' : ''
|
||||||
</div>
|
</div>
|
||||||
<div class="topbar-right">
|
<div class="topbar-right">
|
||||||
<img src="{{ asset('images/icon/sidebar/notif.png') }}" class="topbar-icon" alt="Notification">
|
<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">
|
|
||||||
|
@php $admin = Auth::guard('admin')->user(); @endphp
|
||||||
|
@if($admin->foto_profil)
|
||||||
|
<a href="{{ route('admin.profile.edit') }}">
|
||||||
|
<img src="{{ Storage::url($admin->foto_profil) }}" class="topbar-avatar" alt="Profil">
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<a href="{{ route('admin.profile.edit') }}" class="topbar-avatar-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,233 @@
|
||||||
|
@extends('admin.layouts.app')
|
||||||
|
|
||||||
|
@section('title', 'Edit Profil')
|
||||||
|
|
||||||
|
@push('styles')
|
||||||
|
<style>
|
||||||
|
.page-title { font-size: 24px; font-weight: 800; margin-bottom: 6px; }
|
||||||
|
.page-subtitle { font-size: 14px; color: #64748b; margin-bottom: 28px; }
|
||||||
|
|
||||||
|
.profile-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #e5e5e5;
|
||||||
|
padding: 32px;
|
||||||
|
max-width: 560px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foto-wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
padding-bottom: 28px;
|
||||||
|
border-bottom: 1px solid #f1f5f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foto-preview {
|
||||||
|
width: 88px; height: 88px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 3px solid #e6f0ff;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foto-placeholder {
|
||||||
|
width: 88px; height: 88px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #e6f0ff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 3px solid #e6f0ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foto-placeholder svg { width: 40px; height: 40px; color: #2b8ef3; }
|
||||||
|
.foto-info p { font-size: 13px; color: #64748b; margin: 0 0 10px; }
|
||||||
|
|
||||||
|
.btn-upload {
|
||||||
|
display: inline-block;
|
||||||
|
background: #e6f0ff;
|
||||||
|
color: #2b8ef3;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-upload:hover { background: #dbeeff; }
|
||||||
|
|
||||||
|
.field-group { margin-bottom: 18px; }
|
||||||
|
|
||||||
|
.field-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #475569;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-label span {
|
||||||
|
color: #94a3b8;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: 0;
|
||||||
|
font-size: 11px;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-input {
|
||||||
|
width: 100%;
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1.5px solid #e2e8f0;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 11px 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
color: #1e293b;
|
||||||
|
outline: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-input:focus {
|
||||||
|
border-color: #2b8ef3;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 0 0 3px rgba(43,142,243,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider { border: none; border-top: 1px solid #f1f5f9; margin: 24px 0; }
|
||||||
|
|
||||||
|
.btn-save {
|
||||||
|
background: #2b8ef3;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 28px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
box-shadow: 0 4px 14px rgba(43,142,243,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save:hover { background: #1a7ae0; transform: translateY(-1px); }
|
||||||
|
|
||||||
|
.alert-success {
|
||||||
|
background: #f0fdf4;
|
||||||
|
border: 1.5px solid #86efac;
|
||||||
|
color: #166534;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-error {
|
||||||
|
background: #fef2f2;
|
||||||
|
border: 1.5px solid #fca5a5;
|
||||||
|
color: #991b1b;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
@php $admin = Auth::guard('admin')->user(); @endphp
|
||||||
|
|
||||||
|
<h3 class="page-title">Edit Profil</h3>
|
||||||
|
<p class="page-subtitle">Perbarui username, foto profil, dan password akunmu.</p>
|
||||||
|
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="alert-success">✓ {{ session('success') }}</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($errors->any())
|
||||||
|
<div class="alert-error">
|
||||||
|
<ul style="margin:0;padding-left:16px">
|
||||||
|
@foreach($errors->all() as $error)
|
||||||
|
<li>{{ $error }}</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('admin.profile.update') }}" enctype="multipart/form-data">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<div class="profile-card">
|
||||||
|
|
||||||
|
<div class="foto-wrap">
|
||||||
|
@if($admin->foto_profil)
|
||||||
|
<img src="{{ Storage::url($admin->foto_profil) }}" class="foto-preview" id="foto-preview" alt="Foto Profil">
|
||||||
|
@else
|
||||||
|
<div class="foto-placeholder" id="foto-placeholder">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||||
|
<circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<img src="" class="foto-preview" id="foto-preview" alt="" style="display:none">
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="foto-info">
|
||||||
|
<p>Format: JPG, PNG, WEBP. Maks. 2MB.</p>
|
||||||
|
<label for="foto_profil" class="btn-upload">Pilih Foto</label>
|
||||||
|
<input type="file" name="foto_profil" id="foto_profil" accept="image/*" style="display:none">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Username bisa diubah untuk admin --}}
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">Username</label>
|
||||||
|
<input type="text" name="username" class="field-input"
|
||||||
|
value="{{ old('username', $admin->username) }}" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="divider">
|
||||||
|
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">Password Baru <span>(kosongkan jika tidak ingin mengubah)</span></label>
|
||||||
|
<input type="password" name="password" class="field-input"
|
||||||
|
placeholder="Masukkan password baru" autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">Konfirmasi Password Baru</label>
|
||||||
|
<input type="password" name="password_confirmation" class="field-input"
|
||||||
|
placeholder="Ulangi password baru" autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top:8px">
|
||||||
|
<button type="submit" class="btn-save">Simpan Perubahan</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
document.getElementById('foto_profil').addEventListener('change', function () {
|
||||||
|
const file = this.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
const preview = document.getElementById('foto-preview');
|
||||||
|
const placeholder = document.getElementById('foto-placeholder');
|
||||||
|
preview.src = url;
|
||||||
|
preview.style.display = 'block';
|
||||||
|
if (placeholder) placeholder.style.display = 'none';
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
|
@ -9,77 +9,39 @@
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body { font-family: 'Poppins', sans-serif; background-color: #f8f9fa; margin: 0; }
|
||||||
font-family: 'Poppins', sans-serif;
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper { display: flex; min-height: 100vh; }
|
.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; }
|
||||||
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 { text-align: center; margin-bottom: 40px; }
|
||||||
.sidebar-logo img { width: 90px; }
|
.sidebar-logo img { width: 90px; }
|
||||||
|
|
||||||
.sidebar-link {
|
.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; }
|
||||||
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:hover { background: #e6f0ff; color: #1d4ed8; }
|
||||||
.sidebar-link.active { background: #e6f0ff; color: #1d4ed8; }
|
.sidebar-link.active { background: #e6f0ff; color: #1d4ed8; }
|
||||||
|
|
||||||
.sidebar-icon { width: 20px; height: 20px; flex-shrink: 0; }
|
.sidebar-icon { width: 20px; height: 20px; flex-shrink: 0; }
|
||||||
.sidebar-logout { margin-top: auto; }
|
.sidebar-logout { margin-top: auto; }
|
||||||
|
|
||||||
.main { flex: 1; background: #f5f9ff; display: flex; flex-direction: column; }
|
.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; }
|
||||||
background: #2b8ef3;
|
.topbar-left { display: flex; align-items: center; gap: 10px; font-weight: 600; font-size: 16px; }
|
||||||
margin: 20px;
|
|
||||||
padding: 16px 24px;
|
|
||||||
border-radius: 16px;
|
|
||||||
color: white;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar-left {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar-waving { width: 26px; height: 26px; }
|
.topbar-waving { width: 26px; height: 26px; }
|
||||||
|
.topbar-right { display: flex; align-items: center; gap: 14px; }
|
||||||
.topbar-right { display: flex; align-items: center; gap: 16px; }
|
|
||||||
.topbar-icon { width: 24px; height: 24px; cursor: pointer; }
|
.topbar-icon { width: 24px; height: 24px; cursor: pointer; }
|
||||||
|
|
||||||
|
.topbar-avatar { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; border: 2px solid rgba(255,255,255,0.5); cursor: pointer; transition: border-color 0.2s; display: block; }
|
||||||
|
.topbar-avatar:hover { border-color: white; }
|
||||||
|
|
||||||
|
.topbar-avatar-icon { width: 36px; height: 36px; border-radius: 50%; background: rgba(255,255,255,0.2); border: 2px solid rgba(255,255,255,0.4); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background 0.2s; flex-shrink: 0; text-decoration: none; }
|
||||||
|
.topbar-avatar-icon:hover { background: rgba(255,255,255,0.3); }
|
||||||
|
.topbar-avatar-icon svg { width: 20px; height: 20px; stroke: white; }
|
||||||
|
|
||||||
.content { padding: 20px 30px; flex: 1; }
|
.content { padding: 20px 30px; flex: 1; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@stack('styles')
|
@stack('styles')
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
|
|
||||||
|
|
@ -88,40 +50,23 @@
|
||||||
<img src="{{ asset('images/logo/logosmk.png') }}" alt="Logo">
|
<img src="{{ asset('images/logo/logosmk.png') }}" alt="Logo">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="{{ route('guru.dashboard') }}"
|
<a href="{{ route('guru.dashboard') }}" class="sidebar-link {{ request()->routeIs('guru.dashboard') ? 'active' : '' }}">
|
||||||
class="sidebar-link {{ request()->routeIs('guru.dashboard') ? 'active' : '' }}">
|
<img src="{{ asset('images/icon/sidebar/home.png') }}" class="sidebar-icon"><span>Dashboard</span>
|
||||||
<img src="{{ asset('images/icon/sidebar/home.png') }}" class="sidebar-icon">
|
|
||||||
<span>Dashboard</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ route('guru.guru.index') }}" class="sidebar-link {{ request()->routeIs('guru.guru.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('guru.guru.index') }}"
|
<img src="{{ asset('images/icon/sidebar/guru.png') }}" class="sidebar-icon"><span>Daftar Guru</span>
|
||||||
class="sidebar-link {{ request()->routeIs('guru.guru.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/guru.png') }}" class="sidebar-icon">
|
|
||||||
<span>Daftar Guru</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ route('guru.kelas.index') }}" class="sidebar-link {{ request()->routeIs('guru.kelas.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('guru.kelas.index') }}"
|
<img src="{{ asset('images/icon/sidebar/kelas.png') }}" class="sidebar-icon"><span>Daftar Kelas</span>
|
||||||
class="sidebar-link {{ request()->routeIs('guru.kelas.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/kelas.png') }}" class="sidebar-icon">
|
|
||||||
<span>Daftar Kelas</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ route('guru.siswa.index') }}" class="sidebar-link {{ request()->routeIs('guru.siswa.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('guru.siswa.index') }}"
|
<img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon"><span>Daftar Siswa</span>
|
||||||
class="sidebar-link {{ request()->routeIs('guru.siswa.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon">
|
|
||||||
<span>Daftar Siswa</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ route('guru.mapel.index') }}" class="sidebar-link {{ request()->routeIs('guru.mapel.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('guru.mapel.index') }}"
|
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon"><span>Mata Pelajaran</span>
|
||||||
class="sidebar-link {{ request()->routeIs('guru.mapel.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon">
|
|
||||||
<span>Mata Pelajaran</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ route('guru.leaderboard.index') }}" class="sidebar-link {{ request()->routeIs('guru.leaderboard.*') ? 'active' : '' }}">
|
||||||
<a href="{{ route('guru.leaderboard.index') }}"
|
<img src="{{ asset('images/icon/sidebar/lb.png') }}" class="sidebar-icon"><span>Leaderboard</span>
|
||||||
class="sidebar-link {{ request()->routeIs('guru.leaderboard.*') ? 'active' : '' }}">
|
|
||||||
<img src="{{ asset('images/icon/sidebar/lb.png') }}" class="sidebar-icon">
|
|
||||||
<span>Leaderboard</span>
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<form action="{{ route('guru.logout') }}" method="POST" class="sidebar-logout">
|
<form action="{{ route('guru.logout') }}" method="POST" class="sidebar-logout">
|
||||||
|
|
@ -138,7 +83,19 @@ class="sidebar-link {{ request()->routeIs('guru.leaderboard.*') ? 'active' : ''
|
||||||
</div>
|
</div>
|
||||||
<div class="topbar-right">
|
<div class="topbar-right">
|
||||||
<img src="{{ asset('images/icon/sidebar/notif.png') }}" class="topbar-icon" alt="Notification">
|
<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">
|
|
||||||
|
@php $guru = Auth::guard('guru')->user(); @endphp
|
||||||
|
@if($guru->foto_profil)
|
||||||
|
<a href="{{ route('guru.profile.edit') }}">
|
||||||
|
<img src="{{ Storage::url($guru->foto_profil) }}" class="topbar-avatar" alt="Profil">
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<a href="{{ route('guru.profile.edit') }}" class="topbar-avatar-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
@ -148,7 +105,6 @@ class="sidebar-link {{ request()->routeIs('guru.leaderboard.*') ? 'active' : ''
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
@stack('scripts')
|
@stack('scripts')
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,243 @@
|
||||||
|
@extends('guru.layouts.app')
|
||||||
|
|
||||||
|
@section('title', 'Edit Profil')
|
||||||
|
|
||||||
|
@push('styles')
|
||||||
|
<style>
|
||||||
|
.page-title { font-size: 24px; font-weight: 800; margin-bottom: 6px; }
|
||||||
|
.page-subtitle { font-size: 14px; color: #64748b; margin-bottom: 28px; }
|
||||||
|
|
||||||
|
.profile-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #e5e5e5;
|
||||||
|
padding: 32px;
|
||||||
|
max-width: 560px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foto-wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
padding-bottom: 28px;
|
||||||
|
border-bottom: 1px solid #f1f5f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foto-preview {
|
||||||
|
width: 88px; height: 88px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 3px solid #e6f0ff;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foto-placeholder {
|
||||||
|
width: 88px; height: 88px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #e6f0ff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 3px solid #e6f0ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foto-placeholder svg { width: 40px; height: 40px; color: #2b8ef3; }
|
||||||
|
.foto-info p { font-size: 13px; color: #64748b; margin: 0 0 10px; }
|
||||||
|
|
||||||
|
.btn-upload {
|
||||||
|
display: inline-block;
|
||||||
|
background: #e6f0ff;
|
||||||
|
color: #2b8ef3;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-upload:hover { background: #dbeeff; }
|
||||||
|
|
||||||
|
.field-group { margin-bottom: 18px; }
|
||||||
|
|
||||||
|
.field-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #475569;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-label span {
|
||||||
|
color: #94a3b8;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: 0;
|
||||||
|
font-size: 11px;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-input {
|
||||||
|
width: 100%;
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1.5px solid #e2e8f0;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 11px 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
color: #1e293b;
|
||||||
|
outline: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-input:focus {
|
||||||
|
border-color: #2b8ef3;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 0 0 3px rgba(43,142,243,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-input:disabled {
|
||||||
|
background: #f1f5f9;
|
||||||
|
color: #94a3b8;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider { border: none; border-top: 1px solid #f1f5f9; margin: 24px 0; }
|
||||||
|
|
||||||
|
.btn-save {
|
||||||
|
background: #2b8ef3;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 28px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
box-shadow: 0 4px 14px rgba(43,142,243,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save:hover { background: #1a7ae0; transform: translateY(-1px); }
|
||||||
|
|
||||||
|
.alert-success {
|
||||||
|
background: #f0fdf4;
|
||||||
|
border: 1.5px solid #86efac;
|
||||||
|
color: #166534;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-error {
|
||||||
|
background: #fef2f2;
|
||||||
|
border: 1.5px solid #fca5a5;
|
||||||
|
color: #991b1b;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
@php $guru = Auth::guard('guru')->user(); @endphp
|
||||||
|
|
||||||
|
<h3 class="page-title">Edit Profil</h3>
|
||||||
|
<p class="page-subtitle">Perbarui foto profil dan password akunmu.</p>
|
||||||
|
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="alert-success">✓ {{ session('success') }}</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($errors->any())
|
||||||
|
<div class="alert-error">
|
||||||
|
<ul style="margin:0;padding-left:16px">
|
||||||
|
@foreach($errors->all() as $error)
|
||||||
|
<li>{{ $error }}</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('guru.profile.update') }}" enctype="multipart/form-data">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<div class="profile-card">
|
||||||
|
|
||||||
|
<div class="foto-wrap">
|
||||||
|
@if($guru->foto_profil)
|
||||||
|
<img src="{{ Storage::url($guru->foto_profil) }}" class="foto-preview" id="foto-preview" alt="Foto Profil">
|
||||||
|
@else
|
||||||
|
<div class="foto-placeholder" id="foto-placeholder">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||||
|
<circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<img src="" class="foto-preview" id="foto-preview" alt="" style="display:none">
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="foto-info">
|
||||||
|
<p>Format: JPG, PNG, WEBP. Maks. 2MB.</p>
|
||||||
|
<label for="foto_profil" class="btn-upload">Pilih Foto</label>
|
||||||
|
<input type="file" name="foto_profil" id="foto_profil" accept="image/*" style="display:none">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">NIP <span>(tidak dapat diubah)</span></label>
|
||||||
|
<input type="text" class="field-input" value="{{ $guru->nip }}" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">Nama Lengkap <span>(tidak dapat diubah)</span></label>
|
||||||
|
<input type="text" class="field-input" value="{{ $guru->nama }}" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="divider">
|
||||||
|
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">Password Baru <span>(kosongkan jika tidak ingin mengubah)</span></label>
|
||||||
|
<input type="password" name="password" class="field-input"
|
||||||
|
placeholder="Masukkan password baru" autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">Konfirmasi Password Baru</label>
|
||||||
|
<input type="password" name="password_confirmation" class="field-input"
|
||||||
|
placeholder="Ulangi password baru" autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top:8px">
|
||||||
|
<button type="submit" class="btn-save">Simpan Perubahan</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
document.getElementById('foto_profil').addEventListener('change', function () {
|
||||||
|
const file = this.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
const preview = document.getElementById('foto-preview');
|
||||||
|
const placeholder = document.getElementById('foto-placeholder');
|
||||||
|
preview.src = url;
|
||||||
|
preview.style.display = 'block';
|
||||||
|
if (placeholder) placeholder.style.display = 'none';
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
|
@ -35,28 +35,16 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default: collapsed saat pertama load */
|
|
||||||
.sidebar.collapsed {
|
.sidebar.collapsed {
|
||||||
width: 0;
|
width: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-logo {
|
.sidebar-logo { text-align: center; margin-bottom: 40px; white-space: nowrap; }
|
||||||
text-align: center;
|
.sidebar-logo img { width: 90px; }
|
||||||
margin-bottom: 40px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-logo img {
|
.sidebar-menu { display: flex; flex-direction: column; white-space: nowrap; }
|
||||||
width: 90px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-menu {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-link {
|
.sidebar-link {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -71,42 +59,19 @@
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-link:hover {
|
.sidebar-link:hover { background: #e6f0ff; color: #1d4ed8; }
|
||||||
background: #e6f0ff;
|
.sidebar-link.active { background: #e6f0ff; color: #1d4ed8; }
|
||||||
color: #1d4ed8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-link.active {
|
.sidebar-icon { width: 20px; height: 20px; flex-shrink: 0; }
|
||||||
background: #e6f0ff;
|
.sidebar-logout { margin-top: auto; }
|
||||||
color: #1d4ed8;
|
.sidebar-logout button { width: 100%; border: none; background: transparent; color: #ef4444; font-weight: 600; padding: 10px; text-align: left; }
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-icon {
|
/* ===== TOGGLE BUTTON ===== */
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===== TOGGLE ARROW BUTTON ===== */
|
|
||||||
.sidebar-toggle-btn {
|
.sidebar-toggle-btn {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
left: 260px; /* sama dengan lebar sidebar saat terbuka */
|
left: 260px;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
|
|
@ -121,19 +86,11 @@
|
||||||
box-shadow: 2px 0 8px rgba(43, 142, 243, 0.3);
|
box-shadow: 2px 0 8px rgba(43, 142, 243, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-toggle-btn:hover {
|
.sidebar-toggle-btn:hover { background: #1a7ae0; }
|
||||||
background: #1a7ae0;
|
.sidebar-toggle-btn.collapsed { left: 0; }
|
||||||
}
|
|
||||||
|
|
||||||
/* Posisi tombol saat sidebar collapsed */
|
|
||||||
.sidebar-toggle-btn.collapsed {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Arrow icon SVG */
|
|
||||||
.toggle-arrow {
|
.toggle-arrow {
|
||||||
width: 12px;
|
width: 12px; height: 12px;
|
||||||
height: 12px;
|
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: white;
|
stroke: white;
|
||||||
stroke-width: 2.5;
|
stroke-width: 2.5;
|
||||||
|
|
@ -142,20 +99,10 @@
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Saat collapsed, panah mengarah ke kanan (buka) */
|
.sidebar-toggle-btn.collapsed .toggle-arrow { transform: rotate(180deg); }
|
||||||
.sidebar-toggle-btn.collapsed .toggle-arrow {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===== MAIN ===== */
|
/* ===== MAIN ===== */
|
||||||
.main {
|
.main { flex: 1; background: #f5f9ff; display: flex; flex-direction: column; transition: all 0.3s ease; min-width: 0; }
|
||||||
flex: 1;
|
|
||||||
background: #f5f9ff;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
min-width: 0; /* prevent overflow */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TOPBAR */
|
/* TOPBAR */
|
||||||
.topbar {
|
.topbar {
|
||||||
|
|
@ -169,31 +116,40 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topbar-left {
|
.topbar-left { font-weight: 600; font-size: 16px; display: flex; align-items: center; gap: 10px; }
|
||||||
font-weight: 600;
|
.topbar-right { display: flex; align-items: center; gap: 14px; }
|
||||||
font-size: 16px;
|
.topbar-icon { width: 24px; height: 24px; cursor: pointer; }
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topbar-right {
|
/* Foto profil di topbar */
|
||||||
display: flex;
|
.topbar-avatar {
|
||||||
align-items: center;
|
width: 36px; height: 36px;
|
||||||
gap: 16px;
|
border-radius: 50%;
|
||||||
}
|
object-fit: cover;
|
||||||
|
border: 2px solid rgba(255,255,255,0.5);
|
||||||
.topbar-icon {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CONTENT */
|
.topbar-avatar:hover { border-color: white; }
|
||||||
.content {
|
|
||||||
padding: 20px 30px;
|
.topbar-avatar-icon {
|
||||||
flex: 1;
|
width: 36px; height: 36px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
border: 2px solid rgba(255,255,255,0.4);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.topbar-avatar-icon:hover { background: rgba(255,255,255,0.3); }
|
||||||
|
.topbar-avatar-icon svg { width: 20px; height: 20px; stroke: white; }
|
||||||
|
|
||||||
|
.content { padding: 20px 30px; flex: 1; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@stack('styles')
|
@stack('styles')
|
||||||
|
|
@ -202,38 +158,32 @@
|
||||||
<body>
|
<body>
|
||||||
<div class="siswa-wrapper">
|
<div class="siswa-wrapper">
|
||||||
|
|
||||||
<!-- SIDEBAR (collapsed by default) -->
|
|
||||||
<aside class="sidebar collapsed" id="mainSidebar">
|
<aside class="sidebar collapsed" id="mainSidebar">
|
||||||
<div class="sidebar-logo">
|
<div class="sidebar-logo">
|
||||||
<img src="{{ asset('images/logo/logosmk.png') }}" alt="Logo SMK">
|
<img src="{{ asset('images/logo/logosmk.png') }}" alt="Logo SMK">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="sidebar-menu">
|
<nav class="sidebar-menu">
|
||||||
|
|
||||||
<a href="{{ route('siswa.dashboard') }}"
|
<a href="{{ route('siswa.dashboard') }}"
|
||||||
class="sidebar-link {{ request()->routeIs('siswa.dashboard') ? 'active' : '' }}">
|
class="sidebar-link {{ request()->routeIs('siswa.dashboard') ? 'active' : '' }}">
|
||||||
<img src="{{ asset('images/icon/sidebar/home.png') }}" class="sidebar-icon" alt="">
|
<img src="{{ asset('images/icon/sidebar/home.png') }}" class="sidebar-icon" alt="">
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('siswa.materi.index') }}"
|
<a href="{{ route('siswa.materi.index') }}"
|
||||||
class="sidebar-link {{ request()->routeIs('siswa.materi*') ? 'active' : '' }}">
|
class="sidebar-link {{ request()->routeIs('siswa.materi*') ? 'active' : '' }}">
|
||||||
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt="">
|
<img src="{{ asset('images/icon/sidebar/mapel.png') }}" class="sidebar-icon" alt="">
|
||||||
<span>Materi</span>
|
<span>Materi</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('siswa.tugas.index') }}"
|
<a href="{{ route('siswa.tugas.index') }}"
|
||||||
class="sidebar-link {{ request()->routeIs('siswa.tugas*') ? 'active' : '' }}">
|
class="sidebar-link {{ request()->routeIs('siswa.tugas*') ? 'active' : '' }}">
|
||||||
<img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon" alt="">
|
<img src="{{ asset('images/icon/sidebar/siswa.png') }}" class="sidebar-icon" alt="">
|
||||||
<span>Tugas</span>
|
<span>Tugas</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('siswa.challenge.index') }}"
|
<a href="{{ route('siswa.challenge.index') }}"
|
||||||
class="sidebar-link {{ request()->routeIs('siswa.challenge*') ? 'active' : '' }}">
|
class="sidebar-link {{ request()->routeIs('siswa.challenge*') ? 'active' : '' }}">
|
||||||
<img src="{{ asset('images/icon/sidebar/challenge.png') }}" class="sidebar-icon" alt="">
|
<img src="{{ asset('images/icon/sidebar/challenge.png') }}" class="sidebar-icon" alt="">
|
||||||
<span>Challenge</span>
|
<span>Challenge</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a href="{{ route('siswa.leaderboard.index') }}"
|
<a href="{{ route('siswa.leaderboard.index') }}"
|
||||||
class="sidebar-link {{ request()->routeIs('siswa.leaderboard*') ? 'active' : '' }}">
|
class="sidebar-link {{ request()->routeIs('siswa.leaderboard*') ? 'active' : '' }}">
|
||||||
<img src="{{ asset('images/icon/sidebar/lb.png') }}" class="sidebar-icon" alt="">
|
<img src="{{ asset('images/icon/sidebar/lb.png') }}" class="sidebar-icon" alt="">
|
||||||
|
|
@ -243,24 +193,18 @@ class="sidebar-link {{ request()->routeIs('siswa.leaderboard*') ? 'active' : ''
|
||||||
|
|
||||||
<form action="{{ route('siswa.logout') }}" method="POST" class="sidebar-logout">
|
<form action="{{ route('siswa.logout') }}" method="POST" class="sidebar-logout">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-danger w-100">
|
<button type="submit" class="btn btn-danger w-100">Logout</button>
|
||||||
Logout
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- TOGGLE ARROW BUTTON (collapsed by default karena sidebar tertutup) -->
|
|
||||||
<button class="sidebar-toggle-btn collapsed" id="sidebarToggleBtn" title="Toggle Sidebar">
|
<button class="sidebar-toggle-btn collapsed" id="sidebarToggleBtn" title="Toggle Sidebar">
|
||||||
<!-- Panah kiri (← artinya tutup sidebar) -->
|
|
||||||
<svg class="toggle-arrow" viewBox="0 0 24 24">
|
<svg class="toggle-arrow" viewBox="0 0 24 24">
|
||||||
<polyline points="15 18 9 12 15 6"></polyline>
|
<polyline points="15 18 9 12 15 6"></polyline>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- MAIN -->
|
|
||||||
<div class="main" id="mainContent">
|
<div class="main" id="mainContent">
|
||||||
|
|
||||||
<!-- TOPBAR -->
|
|
||||||
<header class="topbar">
|
<header class="topbar">
|
||||||
<div class="topbar-left">
|
<div class="topbar-left">
|
||||||
👋 Hai, {{ Auth::guard('siswa')->user()->nama ?? 'Siswa' }}
|
👋 Hai, {{ Auth::guard('siswa')->user()->nama ?? 'Siswa' }}
|
||||||
|
|
@ -268,62 +212,47 @@ class="sidebar-link {{ request()->routeIs('siswa.leaderboard*') ? 'active' : ''
|
||||||
|
|
||||||
<div class="topbar-right">
|
<div class="topbar-right">
|
||||||
<img src="{{ asset('images/icon/sidebar/notif.png') }}" class="topbar-icon" alt="Notification">
|
<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">
|
|
||||||
|
{{-- Foto profil atau icon default --}}
|
||||||
|
@php $siswa = Auth::guard('siswa')->user(); @endphp
|
||||||
|
@if($siswa->foto_profil)
|
||||||
|
<a href="{{ route('siswa.profile.edit') }}">
|
||||||
|
<img src="{{ Storage::url($siswa->foto_profil) }}"
|
||||||
|
class="topbar-avatar" alt="Profil">
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<a href="{{ route('siswa.profile.edit') }}" class="topbar-avatar-icon">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- CONTENT -->
|
|
||||||
<main class="content">
|
<main class="content">
|
||||||
@yield('content')
|
@yield('content')
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const sidebar = document.getElementById('mainSidebar');
|
const sidebar = document.getElementById('mainSidebar');
|
||||||
const toggleBtn = document.getElementById('sidebarToggleBtn');
|
const toggleBtn = document.getElementById('sidebarToggleBtn');
|
||||||
const SIDEBAR_W = 260; // harus sama dengan CSS .sidebar width
|
const SIDEBAR_W = 260;
|
||||||
|
|
||||||
function updateTogglePosition(isCollapsed) {
|
function updateTogglePosition(isCollapsed) {
|
||||||
if (isCollapsed) {
|
toggleBtn.style.left = isCollapsed ? '0px' : SIDEBAR_W + 'px';
|
||||||
toggleBtn.style.left = '0px';
|
isCollapsed ? toggleBtn.classList.add('collapsed') : toggleBtn.classList.remove('collapsed');
|
||||||
toggleBtn.classList.add('collapsed');
|
|
||||||
} else {
|
|
||||||
toggleBtn.style.left = SIDEBAR_W + 'px';
|
|
||||||
toggleBtn.classList.remove('collapsed');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleBtn.addEventListener('click', function () {
|
toggleBtn.addEventListener('click', function () {
|
||||||
const isCurrentlyCollapsed = sidebar.classList.contains('collapsed');
|
const isCollapsed = sidebar.classList.contains('collapsed');
|
||||||
|
sidebar.classList.toggle('collapsed');
|
||||||
if (isCurrentlyCollapsed) {
|
updateTogglePosition(!isCollapsed);
|
||||||
// Buka sidebar
|
localStorage.setItem('sidebarOpen', isCollapsed ? 'true' : 'false');
|
||||||
sidebar.classList.remove('collapsed');
|
|
||||||
updateTogglePosition(false);
|
|
||||||
localStorage.setItem('sidebarOpen', 'true');
|
|
||||||
} else {
|
|
||||||
// Tutup sidebar
|
|
||||||
sidebar.classList.add('collapsed');
|
|
||||||
updateTogglePosition(true);
|
|
||||||
localStorage.setItem('sidebarOpen', 'false');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tidak perlu restore dari localStorage karena kita mau selalu collapsed saat login baru.
|
|
||||||
// Tapi kalau mau ingat preferensi user dalam satu sesi browsing, uncomment ini:
|
|
||||||
/*
|
|
||||||
window.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const saved = localStorage.getItem('sidebarOpen');
|
|
||||||
if (saved === 'true') {
|
|
||||||
sidebar.classList.remove('collapsed');
|
|
||||||
updateTogglePosition(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@stack('scripts')
|
@stack('scripts')
|
||||||
|
|
|
||||||
|
|
@ -7,137 +7,62 @@
|
||||||
.page-title { font-size: 28px; font-weight: 800; margin-top: -20px; margin-bottom: 6px; }
|
.page-title { font-size: 28px; font-weight: 800; margin-top: -20px; margin-bottom: 6px; }
|
||||||
.page-subtitle { font-size: 14px; color: #64748b; margin-bottom: 24px; }
|
.page-subtitle { font-size: 14px; color: #64748b; margin-bottom: 24px; }
|
||||||
|
|
||||||
/* Podium top 3 */
|
.podium-wrap { display: flex; align-items: flex-end; justify-content: center; gap: 12px; margin-bottom: 32px; }
|
||||||
.podium-wrap {
|
.podium-item { display: flex; flex-direction: column; align-items: center; gap: 8px; }
|
||||||
display: flex;
|
|
||||||
align-items: flex-end;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 12px;
|
|
||||||
margin-bottom: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.podium-item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.podium-avatar {
|
.podium-avatar {
|
||||||
width: 56px;
|
|
||||||
height: 56px;
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: flex;
|
display: flex; align-items: center; justify-content: center;
|
||||||
align-items: center;
|
font-size: 22px; font-weight: 800; color: white;
|
||||||
justify-content: center;
|
position: relative; overflow: hidden; flex-shrink: 0;
|
||||||
font-size: 22px;
|
width: 56px; height: 56px;
|
||||||
font-weight: 800;
|
|
||||||
color: white;
|
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.podium-crown {
|
.podium-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
|
||||||
position: absolute;
|
.podium-crown { position: absolute; top: -16px; font-size: 18px; z-index: 1; }
|
||||||
top: -16px;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rank-1 .podium-avatar { background: linear-gradient(135deg, #f59e0b, #d97706); width: 68px; height: 68px; font-size: 26px; }
|
.rank-1 .podium-avatar { background: linear-gradient(135deg,#f59e0b,#d97706); width:68px; height:68px; font-size:26px; }
|
||||||
.rank-2 .podium-avatar { background: linear-gradient(135deg, #94a3b8, #64748b); }
|
.rank-2 .podium-avatar { background: linear-gradient(135deg,#94a3b8,#64748b); }
|
||||||
.rank-3 .podium-avatar { background: linear-gradient(135deg, #f97316, #ea580c); }
|
.rank-3 .podium-avatar { background: linear-gradient(135deg,#f97316,#ea580c); }
|
||||||
|
|
||||||
.podium-name { font-size: 13px; font-weight: 700; color: #1e293b; text-align: center; max-width: 90px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
.podium-name { font-size:13px; font-weight:700; color:#1e293b; text-align:center; max-width:90px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
||||||
.podium-exp { font-size: 12px; color: #64748b; }
|
.podium-exp { font-size:12px; color:#64748b; }
|
||||||
|
|
||||||
.podium-bar {
|
.podium-bar { border-radius:12px 12px 0 0; width:80px; display:flex; align-items:center; justify-content:center; font-size:20px; font-weight:800; color:white; }
|
||||||
border-radius: 12px 12px 0 0;
|
.rank-1 .podium-bar { height:80px; background:linear-gradient(135deg,#f59e0b,#d97706); }
|
||||||
width: 80px;
|
.rank-2 .podium-bar { height:60px; background:linear-gradient(135deg,#94a3b8,#64748b); }
|
||||||
display: flex;
|
.rank-3 .podium-bar { height:44px; background:linear-gradient(135deg,#f97316,#ea580c); }
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 800;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rank-1 .podium-bar { height: 80px; background: linear-gradient(135deg, #f59e0b, #d97706); }
|
.my-rank-banner { background:linear-gradient(135deg,#667eea,#764ba2); border-radius:16px; padding:16px 20px; color:white; display:flex; align-items:center; gap:16px; margin-bottom:20px; }
|
||||||
.rank-2 .podium-bar { height: 60px; background: linear-gradient(135deg, #94a3b8, #64748b); }
|
.my-rank-avatar { width:48px; height:48px; border-radius:50%; object-fit:cover; border:2px solid rgba(255,255,255,0.5); flex-shrink:0; }
|
||||||
.rank-3 .podium-bar { height: 44px; background: linear-gradient(135deg, #f97316, #ea580c); }
|
.my-rank-avatar-placeholder { width:48px; height:48px; border-radius:50%; background:rgba(255,255,255,0.2); display:flex; align-items:center; justify-content:center; font-size:20px; font-weight:800; flex-shrink:0; }
|
||||||
|
.my-rank-num { font-size:36px; font-weight:800; line-height:1; }
|
||||||
|
.my-rank-info { flex:1; }
|
||||||
|
.my-rank-label { font-size:12px; opacity:0.8; margin-bottom:2px; }
|
||||||
|
.my-rank-nama { font-size:16px; font-weight:700; }
|
||||||
|
.my-rank-exp { font-size:13px; opacity:0.9; }
|
||||||
|
|
||||||
/* My rank banner */
|
.custom-card { background:white; border-radius:20px; border:2px solid #e5e5e5; padding:22px; }
|
||||||
.my-rank-banner {
|
.section-title { font-size:15px; font-weight:700; color:#1e293b; margin-bottom:16px; }
|
||||||
background: linear-gradient(135deg, #667eea, #764ba2);
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 16px 20px;
|
|
||||||
color: white;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 16px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.my-rank-num {
|
.lb-row { display:flex; align-items:center; gap:12px; padding:10px 14px; border-radius:12px; margin-bottom:8px; transition:background 0.15s; }
|
||||||
font-size: 36px;
|
.lb-row:hover { background:#f8fafc; }
|
||||||
font-weight: 800;
|
.lb-row.highlight { background:#f0eeff; border:2px solid #c4b5fd; }
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.my-rank-info { flex: 1; }
|
.lb-rank { width:32px; height:32px; border-radius:50%; background:#e2e8f0; display:flex; align-items:center; justify-content:center; font-size:13px; font-weight:700; color:#64748b; flex-shrink:0; }
|
||||||
.my-rank-label { font-size: 12px; opacity: 0.8; margin-bottom: 2px; }
|
.lb-rank.gold { background:#fef3c7; color:#d97706; }
|
||||||
.my-rank-nama { font-size: 16px; font-weight: 700; }
|
.lb-rank.silver { background:#f1f5f9; color:#64748b; }
|
||||||
.my-rank-exp { font-size: 13px; opacity: 0.9; }
|
.lb-rank.bronze { background:#ffedd5; color:#ea580c; }
|
||||||
|
|
||||||
/* Tabel */
|
.lb-avatar { width:36px; height:36px; border-radius:50%; object-fit:cover; flex-shrink:0; border:2px solid #e2e8f0; }
|
||||||
.custom-card { background: white; border-radius: 20px; border: 2px solid #e5e5e5; padding: 22px; }
|
.lb-avatar-placeholder { width:36px; height:36px; border-radius:50%; background:#e6f0ff; display:flex; align-items:center; justify-content:center; font-size:14px; font-weight:700; color:#2b8ef3; flex-shrink:0; }
|
||||||
.section-title { font-size: 15px; font-weight: 700; color: #1e293b; margin-bottom: 16px; }
|
|
||||||
|
|
||||||
.lb-row {
|
.lb-nama { flex:1; font-size:14px; font-weight:600; color:#1e293b; }
|
||||||
display: flex;
|
.lb-nisn { font-size:12px; color:#94a3b8; }
|
||||||
align-items: center;
|
.lb-exp { font-size:14px; font-weight:700; color:#667eea; }
|
||||||
gap: 14px;
|
|
||||||
padding: 12px 14px;
|
|
||||||
border-radius: 12px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
transition: background 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lb-row:hover { background: #f8fafc; }
|
.semester-badge { display:inline-block; background:#f0eeff; color:#667eea; font-size:12px; font-weight:700; padding:4px 12px; border-radius:99px; margin-bottom:20px; }
|
||||||
.lb-row.highlight { background: #f0eeff; border: 2px solid #c4b5fd; }
|
.empty-state { text-align:center; padding:40px 20px; color:#94a3b8; }
|
||||||
|
|
||||||
.lb-rank {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #e2e8f0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #64748b;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lb-rank.gold { background: #fef3c7; color: #d97706; }
|
|
||||||
.lb-rank.silver { background: #f1f5f9; color: #64748b; }
|
|
||||||
.lb-rank.bronze { background: #ffedd5; color: #ea580c; }
|
|
||||||
|
|
||||||
.lb-nama { flex: 1; font-size: 14px; font-weight: 600; color: #1e293b; }
|
|
||||||
.lb-nisn { font-size: 12px; color: #94a3b8; }
|
|
||||||
.lb-exp { font-size: 14px; font-weight: 700; color: #667eea; }
|
|
||||||
|
|
||||||
.semester-badge {
|
|
||||||
display: inline-block;
|
|
||||||
background: #f0eeff;
|
|
||||||
color: #667eea;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 700;
|
|
||||||
padding: 4px 12px;
|
|
||||||
border-radius: 99px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-state { text-align: center; padding: 40px 20px; color: #94a3b8; }
|
|
||||||
</style>
|
</style>
|
||||||
@endpush
|
@endpush
|
||||||
|
|
||||||
|
|
@ -148,9 +73,7 @@
|
||||||
<h3 class="page-title">🏅 Leaderboard</h3>
|
<h3 class="page-title">🏅 Leaderboard</h3>
|
||||||
<p class="page-subtitle">Peringkat siswa berdasarkan total EXP yang dikumpulkan.</p>
|
<p class="page-subtitle">Peringkat siswa berdasarkan total EXP yang dikumpulkan.</p>
|
||||||
|
|
||||||
<span class="semester-badge">
|
<span class="semester-badge">Semester {{ $semester }} · {{ $tahunAjaran }}</span>
|
||||||
Semester {{ $semester }} · {{ $tahunAjaran }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
@if($leaderboard->isEmpty())
|
@if($leaderboard->isEmpty())
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
|
|
@ -160,9 +83,8 @@
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
|
|
||||||
{{-- Podium Top 3 --}}
|
|
||||||
@php
|
@php
|
||||||
$top3 = $leaderboard->take(3);
|
$top3 = $leaderboard->take(3);
|
||||||
$first = $top3->firstWhere('ranking', 1);
|
$first = $top3->firstWhere('ranking', 1);
|
||||||
$second = $top3->firstWhere('ranking', 2);
|
$second = $top3->firstWhere('ranking', 2);
|
||||||
$third = $top3->firstWhere('ranking', 3);
|
$third = $top3->firstWhere('ranking', 3);
|
||||||
|
|
@ -171,31 +93,44 @@
|
||||||
@if($first)
|
@if($first)
|
||||||
<div class="podium-wrap">
|
<div class="podium-wrap">
|
||||||
|
|
||||||
{{-- Rank 2 --}}
|
|
||||||
@if($second)
|
@if($second)
|
||||||
<div class="podium-item rank-2">
|
<div class="podium-item rank-2">
|
||||||
<div class="podium-avatar">{{ strtoupper(substr($second['nama'], 0, 1)) }}</div>
|
<div class="podium-avatar">
|
||||||
|
@if(!empty($second['foto_profil']))
|
||||||
|
<img src="{{ Storage::url($second['foto_profil']) }}" alt="">
|
||||||
|
@else
|
||||||
|
{{ strtoupper(substr($second['nama'], 0, 1)) }}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
<div class="podium-name">{{ $second['nama'] }}</div>
|
<div class="podium-name">{{ $second['nama'] }}</div>
|
||||||
<div class="podium-exp">⭐ {{ number_format($second['exp']) }}</div>
|
<div class="podium-exp">⭐ {{ number_format($second['exp']) }}</div>
|
||||||
<div class="podium-bar">2</div>
|
<div class="podium-bar">2</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- Rank 1 --}}
|
|
||||||
<div class="podium-item rank-1">
|
<div class="podium-item rank-1">
|
||||||
<div class="podium-avatar">
|
<div class="podium-avatar">
|
||||||
<span class="podium-crown">👑</span>
|
<span class="podium-crown">👑</span>
|
||||||
{{ strtoupper(substr($first['nama'], 0, 1)) }}
|
@if(!empty($first['foto_profil']))
|
||||||
|
<img src="{{ Storage::url($first['foto_profil']) }}" alt="">
|
||||||
|
@else
|
||||||
|
{{ strtoupper(substr($first['nama'], 0, 1)) }}
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="podium-name">{{ $first['nama'] }}</div>
|
<div class="podium-name">{{ $first['nama'] }}</div>
|
||||||
<div class="podium-exp">⭐ {{ number_format($first['exp']) }}</div>
|
<div class="podium-exp">⭐ {{ number_format($first['exp']) }}</div>
|
||||||
<div class="podium-bar">1</div>
|
<div class="podium-bar">1</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- Rank 3 --}}
|
|
||||||
@if($third)
|
@if($third)
|
||||||
<div class="podium-item rank-3">
|
<div class="podium-item rank-3">
|
||||||
<div class="podium-avatar">{{ strtoupper(substr($third['nama'], 0, 1)) }}</div>
|
<div class="podium-avatar">
|
||||||
|
@if(!empty($third['foto_profil']))
|
||||||
|
<img src="{{ Storage::url($third['foto_profil']) }}" alt="">
|
||||||
|
@else
|
||||||
|
{{ strtoupper(substr($third['nama'], 0, 1)) }}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
<div class="podium-name">{{ $third['nama'] }}</div>
|
<div class="podium-name">{{ $third['nama'] }}</div>
|
||||||
<div class="podium-exp">⭐ {{ number_format($third['exp']) }}</div>
|
<div class="podium-exp">⭐ {{ number_format($third['exp']) }}</div>
|
||||||
<div class="podium-bar">3</div>
|
<div class="podium-bar">3</div>
|
||||||
|
|
@ -205,9 +140,13 @@
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- My Rank Banner --}}
|
|
||||||
@if($myRank)
|
@if($myRank)
|
||||||
<div class="my-rank-banner">
|
<div class="my-rank-banner">
|
||||||
|
@if(!empty($myRank['foto_profil']))
|
||||||
|
<img src="{{ Storage::url($myRank['foto_profil']) }}" class="my-rank-avatar" alt="">
|
||||||
|
@else
|
||||||
|
<div class="my-rank-avatar-placeholder">{{ strtoupper(substr($myRank['nama'], 0, 1)) }}</div>
|
||||||
|
@endif
|
||||||
<div class="my-rank-num">#{{ $myRank['ranking'] }}</div>
|
<div class="my-rank-num">#{{ $myRank['ranking'] }}</div>
|
||||||
<div class="my-rank-info">
|
<div class="my-rank-info">
|
||||||
<div class="my-rank-label">Posisimu saat ini</div>
|
<div class="my-rank-label">Posisimu saat ini</div>
|
||||||
|
|
@ -218,16 +157,13 @@
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- Tabel semua --}}
|
|
||||||
<div class="custom-card">
|
<div class="custom-card">
|
||||||
<p class="section-title">📋 Semua Peringkat</p>
|
<p class="section-title">📋 Semua Peringkat</p>
|
||||||
|
|
||||||
@foreach($leaderboard as $item)
|
@foreach($leaderboard as $item)
|
||||||
@php
|
@php
|
||||||
$isMe = $item['id_siswa'] === $siswaLogin->id_siswa;
|
$isMe = $item['id_siswa'] === $siswaLogin->id_siswa;
|
||||||
$rankClass = match($item['ranking']) {
|
$rankClass = match($item['ranking']) { 1=>'gold', 2=>'silver', 3=>'bronze', default=>'' };
|
||||||
1 => 'gold', 2 => 'silver', 3 => 'bronze', default => ''
|
|
||||||
};
|
|
||||||
@endphp
|
@endphp
|
||||||
<div class="lb-row {{ $isMe ? 'highlight' : '' }}">
|
<div class="lb-row {{ $isMe ? 'highlight' : '' }}">
|
||||||
<div class="lb-rank {{ $rankClass }}">
|
<div class="lb-rank {{ $rankClass }}">
|
||||||
|
|
@ -237,10 +173,19 @@
|
||||||
@else {{ $item['ranking'] }}
|
@else {{ $item['ranking'] }}
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if(!empty($item['foto_profil']))
|
||||||
|
<img src="{{ Storage::url($item['foto_profil']) }}" class="lb-avatar" alt="">
|
||||||
|
@else
|
||||||
|
<div class="lb-avatar-placeholder">{{ strtoupper(substr($item['nama'], 0, 1)) }}</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<div style="flex:1">
|
<div style="flex:1">
|
||||||
<div class="lb-nama">
|
<div class="lb-nama">
|
||||||
{{ $item['nama'] }}
|
{{ $item['nama'] }}
|
||||||
@if($isMe) <span style="background:#c4b5fd;color:#4c1d95;font-size:10px;padding:2px 7px;border-radius:99px;font-weight:700;margin-left:4px">Kamu</span> @endif
|
@if($isMe)
|
||||||
|
<span style="background:#c4b5fd;color:#4c1d95;font-size:10px;padding:2px 7px;border-radius:99px;font-weight:700;margin-left:4px">Kamu</span>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="lb-nisn">{{ $item['nisn'] }}</div>
|
<div class="lb-nisn">{{ $item['nisn'] }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
@extends('siswa.layouts.app')
|
||||||
|
|
||||||
|
@section('title', 'Edit Profil')
|
||||||
|
|
||||||
|
@push('styles')
|
||||||
|
<style>
|
||||||
|
.page-title { font-size: 24px; font-weight: 800; margin-bottom: 6px; }
|
||||||
|
.page-subtitle { font-size: 14px; color: #64748b; margin-bottom: 28px; }
|
||||||
|
|
||||||
|
.profile-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #e5e5e5;
|
||||||
|
padding: 32px;
|
||||||
|
max-width: 560px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Foto profil */
|
||||||
|
.foto-wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
padding-bottom: 28px;
|
||||||
|
border-bottom: 1px solid #f1f5f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foto-preview {
|
||||||
|
width: 88px; height: 88px;
|
||||||
|
border-radius: 50%;
|
||||||
|
object-fit: cover;
|
||||||
|
border: 3px solid #e6f0ff;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foto-placeholder {
|
||||||
|
width: 88px; height: 88px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #e6f0ff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 3px solid #e6f0ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.foto-placeholder svg { width: 40px; height: 40px; color: #2b8ef3; }
|
||||||
|
|
||||||
|
.foto-info p { font-size: 13px; color: #64748b; margin: 0 0 10px; }
|
||||||
|
|
||||||
|
.btn-upload {
|
||||||
|
display: inline-block;
|
||||||
|
background: #e6f0ff;
|
||||||
|
color: #2b8ef3;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-upload:hover { background: #dbeeff; }
|
||||||
|
|
||||||
|
/* Form fields */
|
||||||
|
.field-group { margin-bottom: 18px; }
|
||||||
|
|
||||||
|
.field-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #475569;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-label span {
|
||||||
|
color: #94a3b8;
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: 0;
|
||||||
|
font-size: 11px;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-input {
|
||||||
|
width: 100%;
|
||||||
|
background: #f8fafc;
|
||||||
|
border: 1.5px solid #e2e8f0;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 11px 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
color: #1e293b;
|
||||||
|
outline: none;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-input:focus {
|
||||||
|
border-color: #2b8ef3;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 0 0 3px rgba(43,142,243,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-input:disabled {
|
||||||
|
background: #f1f5f9;
|
||||||
|
color: #94a3b8;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-hint { font-size: 11px; color: #94a3b8; margin-top: 4px; }
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid #f1f5f9;
|
||||||
|
margin: 24px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save {
|
||||||
|
background: #2b8ef3;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 28px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: 'Poppins', sans-serif;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
box-shadow: 0 4px 14px rgba(43,142,243,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save:hover { background: #1a7ae0; transform: translateY(-1px); }
|
||||||
|
|
||||||
|
.alert-success {
|
||||||
|
background: #f0fdf4;
|
||||||
|
border: 1.5px solid #86efac;
|
||||||
|
color: #166534;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-error {
|
||||||
|
background: #fef2f2;
|
||||||
|
border: 1.5px solid #fca5a5;
|
||||||
|
color: #991b1b;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
@php $siswa = Auth::guard('siswa')->user(); @endphp
|
||||||
|
|
||||||
|
<h3 class="page-title">Edit Profil</h3>
|
||||||
|
<p class="page-subtitle">Perbarui foto profil dan password akunmu.</p>
|
||||||
|
|
||||||
|
@if(session('success'))
|
||||||
|
<div class="alert-success">✓ {{ session('success') }}</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if($errors->any())
|
||||||
|
<div class="alert-error">
|
||||||
|
<ul style="margin:0;padding-left:16px">
|
||||||
|
@foreach($errors->all() as $error)
|
||||||
|
<li>{{ $error }}</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('siswa.profile.update') }}" enctype="multipart/form-data">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<div class="profile-card">
|
||||||
|
|
||||||
|
{{-- Foto Profil --}}
|
||||||
|
<div class="foto-wrap">
|
||||||
|
@if($siswa->foto_profil)
|
||||||
|
<img src="{{ Storage::url($siswa->foto_profil) }}" class="foto-preview" id="foto-preview" alt="Foto Profil">
|
||||||
|
@else
|
||||||
|
<div class="foto-placeholder" id="foto-placeholder">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||||
|
<circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<img src="" class="foto-preview" id="foto-preview" alt="" style="display:none">
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="foto-info">
|
||||||
|
<p>Format: JPG, PNG, WEBP. Maks. 2MB.</p>
|
||||||
|
<label for="foto_profil" class="btn-upload">Pilih Foto</label>
|
||||||
|
<input type="file" name="foto_profil" id="foto_profil" accept="image/*" style="display:none">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Info tidak bisa diubah --}}
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">NISN <span>(tidak dapat diubah)</span></label>
|
||||||
|
<input type="text" class="field-input" value="{{ $siswa->nisn }}" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">Nama Lengkap <span>(tidak dapat diubah)</span></label>
|
||||||
|
<input type="text" class="field-input" value="{{ $siswa->nama }}" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="divider">
|
||||||
|
|
||||||
|
{{-- Password --}}
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">Password Baru <span>(kosongkan jika tidak ingin mengubah)</span></label>
|
||||||
|
<input type="password" name="password" class="field-input"
|
||||||
|
placeholder="Masukkan password baru" autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-group">
|
||||||
|
<label class="field-label">Konfirmasi Password Baru</label>
|
||||||
|
<input type="password" name="password_confirmation" class="field-input"
|
||||||
|
placeholder="Ulangi password baru" autocomplete="new-password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top:8px">
|
||||||
|
<button type="submit" class="btn-save">Simpan Perubahan</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
document.getElementById('foto_profil').addEventListener('change', function () {
|
||||||
|
const file = this.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
const preview = document.getElementById('foto-preview');
|
||||||
|
const placeholder = document.getElementById('foto-placeholder');
|
||||||
|
preview.src = url;
|
||||||
|
preview.style.display = 'block';
|
||||||
|
if (placeholder) placeholder.style.display = 'none';
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
|
|
@ -13,16 +13,16 @@
|
||||||
use App\Http\Controllers\Admin\MapelController as AdminMapelController;
|
use App\Http\Controllers\Admin\MapelController as AdminMapelController;
|
||||||
use App\Http\Controllers\Admin\ChallengeController as AdminChallengeController;
|
use App\Http\Controllers\Admin\ChallengeController as AdminChallengeController;
|
||||||
use App\Http\Controllers\Admin\LeaderboardController as AdminLeaderboardController;
|
use App\Http\Controllers\Admin\LeaderboardController as AdminLeaderboardController;
|
||||||
|
use App\Http\Controllers\Admin\ProfileController as AdminProfileController;
|
||||||
use App\Http\Controllers\Admin\MateriTugasController as AdminMateriTugasController;
|
use App\Http\Controllers\Admin\MateriTugasController as AdminMateriTugasController;
|
||||||
|
|
||||||
|
|
||||||
// GURU CONTROLLERS
|
// GURU CONTROLLERS
|
||||||
use App\Http\Controllers\Guru\LoginController as GuruLoginController;
|
use App\Http\Controllers\Guru\LoginController as GuruLoginController;
|
||||||
use App\Http\Controllers\Guru\DashboardController as GuruDashboardController;
|
use App\Http\Controllers\Guru\DashboardController as GuruDashboardController;
|
||||||
use App\Http\Controllers\Guru\GuruController as GuruGuruController;
|
use App\Http\Controllers\Guru\GuruController as GuruGuruController;
|
||||||
use App\Http\Controllers\Guru\KelasController as GuruKelasController;
|
use App\Http\Controllers\Guru\KelasController as GuruKelasController;
|
||||||
use App\Http\Controllers\Guru\SiswaController as GuruSiswaController;
|
use App\Http\Controllers\Guru\SiswaController as GuruSiswaController;
|
||||||
use App\Http\Controllers\Guru\ProfilController as GuruProfilController;
|
use App\Http\Controllers\Guru\ProfileController as GuruProfileController;
|
||||||
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;
|
||||||
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
use App\Http\Controllers\Siswa\TugasController as SiswaTugasController;
|
use App\Http\Controllers\Siswa\TugasController as SiswaTugasController;
|
||||||
use App\Http\Controllers\Siswa\ChallengeController as SiswaChallengeController;
|
use App\Http\Controllers\Siswa\ChallengeController as SiswaChallengeController;
|
||||||
use App\Http\Controllers\Siswa\LeaderboardController as SiswaLeaderboardController;
|
use App\Http\Controllers\Siswa\LeaderboardController as SiswaLeaderboardController;
|
||||||
|
use App\Http\Controllers\Siswa\ProfileController as SiswaProfileController;
|
||||||
|
|
||||||
// ====================
|
// ====================
|
||||||
// LANDING PAGE
|
// LANDING PAGE
|
||||||
|
|
@ -87,9 +88,8 @@
|
||||||
return view('admin.notif');
|
return view('admin.notif');
|
||||||
})->name('notif');
|
})->name('notif');
|
||||||
|
|
||||||
Route::get('/profil', function () {
|
Route::get('/profile', [AdminProfileController::class, 'edit'])->name('profile.edit');
|
||||||
return view('admin.profil');
|
Route::put('/profile', [AdminProfileController::class, 'update'])->name('profile.update');
|
||||||
})->name('profil');
|
|
||||||
|
|
||||||
// ── GURU ──────────────────────────────────────────────
|
// ── GURU ──────────────────────────────────────────────
|
||||||
Route::get('/guru/kelas-by-mapel', [AdminGuruController::class, 'getKelasByMapel'])
|
Route::get('/guru/kelas-by-mapel', [AdminGuruController::class, 'getKelasByMapel'])
|
||||||
|
|
@ -111,7 +111,6 @@
|
||||||
Route::delete('/tugas/{id}', [AdminMateriTugasController::class, 'destroyTugas'])->name('tugas.destroy');
|
Route::delete('/tugas/{id}', [AdminMateriTugasController::class, 'destroyTugas'])->name('tugas.destroy');
|
||||||
|
|
||||||
// ── CHALLENGE ─────────────────────────────────────────
|
// ── CHALLENGE ─────────────────────────────────────────
|
||||||
// WAJIB di atas Route::resource agar tidak konflik dengan {challenge} wildcard
|
|
||||||
Route::get('/challenge/{id}/edit-data', [AdminChallengeController::class, 'editData'])
|
Route::get('/challenge/{id}/edit-data', [AdminChallengeController::class, 'editData'])
|
||||||
->name('challenge.editData');
|
->name('challenge.editData');
|
||||||
Route::resource('challenge', AdminChallengeController::class);
|
Route::resource('challenge', AdminChallengeController::class);
|
||||||
|
|
@ -155,10 +154,8 @@
|
||||||
Route::get('/tugas/{id}/detail', [GuruMapelController::class, 'detailTugas'])->name('tugas.detail');
|
Route::get('/tugas/{id}/detail', [GuruMapelController::class, 'detailTugas'])->name('tugas.detail');
|
||||||
Route::delete('/tugas/{id}', [GuruMapelController::class, 'destroyTugas'])->name('tugas.destroy');
|
Route::delete('/tugas/{id}', [GuruMapelController::class, 'destroyTugas'])->name('tugas.destroy');
|
||||||
|
|
||||||
|
Route::get('/profile', [GuruProfileController::class, 'edit'])->name('profile.edit');
|
||||||
// Profil (Edit)
|
Route::put('/profile', [GuruProfileController::class, 'update'])->name('profile.update');
|
||||||
Route::get('/profil', [GuruProfilController::class, 'show'])->name('profil.show');
|
|
||||||
Route::put('/profil', [GuruProfilController::class, 'update'])->name('profil.update');
|
|
||||||
|
|
||||||
// LOGOUT GURU
|
// LOGOUT GURU
|
||||||
Route::post('/logout', [GuruLoginController::class, 'logout'])->name('logout');
|
Route::post('/logout', [GuruLoginController::class, 'logout'])->name('logout');
|
||||||
|
|
@ -188,6 +185,10 @@
|
||||||
|
|
||||||
//LEADERBOARD SISWA
|
//LEADERBOARD SISWA
|
||||||
Route::get('/leaderboard', [SiswaLeaderboardController::class, 'index'])->name('leaderboard.index');
|
Route::get('/leaderboard', [SiswaLeaderboardController::class, 'index'])->name('leaderboard.index');
|
||||||
|
|
||||||
|
//PROFILE SISWA
|
||||||
|
Route::get('/profile', [SiswaProfileController::class, 'edit'])->name('profile.edit');
|
||||||
|
Route::put('/profile', [SiswaProfileController::class, 'update'])->name('profile.update');
|
||||||
|
|
||||||
// LOGOUT SISWA
|
// LOGOUT SISWA
|
||||||
Route::post('/logout', [SiswaLoginController::class, 'logout'])->name('logout');
|
Route::post('/logout', [SiswaLoginController::class, 'logout'])->name('logout');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue