Fix tambah admin

This commit is contained in:
ramzdhani11 2026-02-04 19:02:45 +07:00
parent c05f121ecd
commit e08b7f011b
8 changed files with 619 additions and 180 deletions

View File

@ -0,0 +1,138 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class AdminController extends Controller
{
public function index()
{
if (!session('admin_logged_in')) {
return redirect()->route('admin.login')->with('error', 'Silakan login terlebih dahulu.');
}
$admins = User::where('role', 'admin')->get();
\Log::info('Admins fetched for UI', ['count' => $admins->count(), 'admins' => $admins->pluck('email')->toArray()]);
return view('Admin.manage-admin', compact('admins'));
}
public function store(Request $request)
{
if (!session('admin_logged_in')) {
return response()->json(['error' => 'Unauthorized'], 401);
}
// Debug log
\Log::info('Admin store request data', ['request_data' => $request->all()]);
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6',
'role' => 'required|in:admin'
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$admin = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
'role' => $request->role,
'email_verified_at' => now()
]);
return response()->json(['success' => 'Admin berhasil ditambahkan', 'admin' => $admin]);
}
public function edit($id)
{
if (!session('admin_logged_in')) {
return response()->json(['error' => 'Unauthorized'], 401);
}
$admin = User::findOrFail($id);
return response()->json($admin);
}
public function update(Request $request, $id)
{
if (!session('admin_logged_in')) {
return response()->json(['error' => 'Unauthorized'], 401);
}
$admin = User::findOrFail($id);
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users,email,'.$id,
'role' => 'required|in:admin'
]);
if ($validator->fails()) {
return response()->json(['errors' => $validator->errors()], 422);
}
$admin->update([
'name' => $request->name,
'email' => $request->email,
'role' => $request->role
]);
if ($request->filled('password')) {
$admin->update(['password' => Hash::make($request->password)]);
}
return response()->json(['success' => 'Admin berhasil diperbarui', 'admin' => $admin]);
}
public function destroy($id)
{
if (!session('admin_logged_in')) {
return response()->json(['error' => 'Unauthorized'], 401);
}
$admin = User::findOrFail($id);
// Prevent deleting the currently logged in admin
if ($admin->id == session('admin_user_id')) {
return response()->json(['error' => 'Tidak dapat menghapus akun yang sedang digunakan'], 422);
}
$admin->delete();
return response()->json(['success' => 'Admin berhasil dihapus']);
}
public function toggleStatus($id)
{
if (!session('admin_logged_in')) {
return response()->json(['error' => 'Unauthorized'], 401);
}
$admin = User::findOrFail($id);
// Prevent deactivating the currently logged in admin
if ($admin->id == session('admin_user_id')) {
return response()->json(['error' => 'Tidak dapat menonaktifkan akun yang sedang digunakan'], 422);
}
// For simplicity, we'll use email_verified_at as status indicator
if ($admin->email_verified_at) {
$admin->update(['email_verified_at' => null]);
$status = 'inactive';
} else {
$admin->update(['email_verified_at' => now()]);
$status = 'active';
}
return response()->json(['success' => "Status admin berhasil diubah menjadi $status", 'status' => $status]);
}
}

View File

@ -13,11 +13,16 @@ class AdminSeeder extends Seeder
*/
public function run(): void
{
// Clear existing admin users first
DB::table('users')->where('role', 'admin')->delete();
// Create single admin user
DB::table('users')->insert([
'name' => 'Admin',
'email' => 'admin@gmail.com',
'password' => Hash::make('admin123'),
'role' => 'admin',
'email_verified_at' => now(),
'created_at' => now(),
'updated_at' => now(),
]);

View File

@ -47,12 +47,12 @@
<div class="w-12 h-12 bg-orange-100 rounded-xl flex items-center justify-center">
<i class="fas fa-users text-orange-600 text-xl"></i>
</div>
<span class="text-xs text-gray-600 font-medium bg-gray-50 px-2 py-1 rounded-full">
0%
<span class="text-xs bg-orange-100 text-orange-800 font-medium px-3 py-1 rounded-full">
{{ App\Models\User::where('role', 'admin')->count() }}
</span>
</div>
<h3 class="text-2xl font-bold text-gray-900 mb-1">5</h3>
<p class="text-sm text-gray-600">Admin Aktif</p>
<h3 class="text-lg font-bold text-gray-900 mb-1">Admin Aktif</h3>
<p class="text-sm text-gray-600">Total admin terdaftar</p>
</div>
<!-- Data Hari Ini Card -->

View File

@ -16,6 +16,9 @@
<!-- Font Awesome for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<!-- Chart.js (only load on pages that need it) -->
@if(request()->routeIs('admin.dashboard') || request()->routeIs('admin.system-statistics'))
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
@ -26,6 +29,155 @@
font-family: 'Inter', sans-serif;
}
/* Dark Mode Styles */
.dark {
background-color: #1a1a1a;
color: #e5e5e5;
}
.dark .bg-white {
background-color: #2d2d2d !important;
}
.dark .bg-gray-50 {
background-color: #1f1f1f !important;
}
.dark .bg-gray-100 {
background-color: #2d2d2d !important;
}
.dark .text-gray-900 {
color: #e5e5e5 !important;
}
.dark .text-gray-800 {
color: #d4d4d4 !important;
}
.dark .text-gray-700 {
color: #b3b3b3 !important;
}
.dark .text-gray-600 {
color: #999999 !important;
}
.dark .text-gray-500 {
color: #808080 !important;
}
.dark .border-gray-200 {
border-color: #404040 !important;
}
.dark .border-gray-300 {
border-color: #404040 !important;
}
.dark .hover\:bg-gray-50:hover {
background-color: #2d2d2d !important;
}
.dark .hover\:bg-gray-100:hover {
background-color: #3d3d3d !important;
}
.dark .hover\:bg-blue-50:hover {
background-color: #1e3a5f !important;
}
.dark .hover\:bg-orange-50:hover {
background-color: #5c3d1e !important;
}
.dark .hover\:bg-red-50:hover {
background-color: #5c1e1e !important;
}
.dark .divide-gray-200 > :not([hidden]) ~ :not([hidden]) {
border-color: #404040 !important;
}
.dark .shadow-sm {
box-shadow: 0 1px 2px 0 rgba(255, 255, 255, 0.05) !important;
}
.dark .bg-gradient-to-r {
background-image: none !important;
}
.dark .btn-primary {
background-color: #dc2626 !important;
}
.dark .btn-primary:hover {
background-color: #b91c1c !important;
}
/* Modal Dark Mode */
.dark .fixed.inset-0 {
background-color: rgba(0, 0, 0, 0.8) !important;
}
.dark .fixed.inset-0 > .bg-white {
background-color: #2d2d2d !important;
color: #e5e5e5 !important;
}
.dark .text-gray-700 {
color: #b3b3b3 !important;
}
/* Form elements dark mode */
.dark input, .dark select, .dark textarea {
background-color: #3d3d3d !important;
border-color: #404040 !important;
color: #e5e5e5 !important;
}
.dark input:focus, .dark select:focus, .dark textarea:focus {
border-color: #dc2626 !important;
}
/* Sidebar dark mode */
.dark .bg-gradient-to-b {
background-image: none !important;
background-color: #1f1f1f !important;
}
.dark .sidebar-link {
color: #b3b3b3 !important;
}
.dark .sidebar-link:hover {
color: #e5e5e5 !important;
background-color: #2d2d2d !important;
}
.dark .sidebar-link.active {
color: #ffffff !important;
background-color: #dc2626 !important;
}
.sidebar-link.active {
background-color: #dc2626 !important;
color: white !important;
}
.sidebar-link:hover {
background-color: #f3f4f6 !important;
}
/* Admin card dark mode */
.dark .hover\:bg-gray-50:hover {
background-color: #2d2d2d !important;
}
.dark .border-t.border-gray-100 {
border-color: #404040 !important;
}
.stat-card {
transition: all 0.3s ease;
}
@ -117,6 +269,11 @@
</div>
<div class="flex items-center space-x-4">
<!-- Dark Mode Toggle -->
<button id="darkModeToggle" class="relative p-2 text-gray-600 hover:text-gray-900 transition-colors" title="Toggle Dark Mode">
<i class="fas fa-moon text-xl" id="darkModeIcon"></i>
</button>
<button class="relative p-2 text-gray-600 hover:text-gray-900 transition-colors">
<i class="fas fa-bell text-xl"></i>
<span class="absolute top-1 right-1 w-2 h-2 bg-red-500 rounded-full"></span>
@ -144,8 +301,42 @@
<!-- Common JavaScript -->
<script>
// Common functionality for all pages
// Dark Mode Toggle
document.addEventListener('DOMContentLoaded', function() {
const darkModeToggle = document.getElementById('darkModeToggle');
const darkModeIcon = document.getElementById('darkModeIcon');
const html = document.documentElement;
// Check for saved theme preference or default to light mode
const currentTheme = localStorage.getItem('theme') || 'light';
if (currentTheme === 'dark') {
html.classList.add('dark');
darkModeIcon.classList.remove('fa-moon');
darkModeIcon.classList.add('fa-sun');
}
// Toggle dark mode
darkModeToggle.addEventListener('click', function() {
const isDark = html.classList.contains('dark');
if (isDark) {
html.classList.remove('dark');
darkModeIcon.classList.remove('fa-sun');
darkModeIcon.classList.add('fa-moon');
localStorage.setItem('theme', 'light');
} else {
html.classList.add('dark');
darkModeIcon.classList.remove('fa-moon');
darkModeIcon.classList.add('fa-sun');
localStorage.setItem('theme', 'dark');
}
// Update chart colors if charts exist
if (window.updateChartTheme) {
updateChartTheme(!isDark);
}
});
// Initialize tooltips and other common UI elements
console.log('Admin Dashboard loaded');
});

View File

@ -25,9 +25,6 @@
<table class="w-full">
<thead class="bg-gray-50 border-b border-gray-200">
<tr>
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Foto
</th>
<th class="px-6 py-4 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Nama
</th>
@ -43,150 +40,53 @@
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<!-- Admin Row 1 -->
<tr class="table-row">
@forelse ($admins as $admin)
<tr class="table-row" data-id="{{ $admin->id }}">
<td class="px-6 py-4 whitespace-nowrap">
<img src="https://picsum.photos/seed/admin1/50/50.jpg"
alt="Admin"
class="w-12 h-12 rounded-full object-cover border-2 border-gray-200">
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">Ahmad Wijaya</div>
<div class="text-xs text-gray-500">Active</div>
<div class="text-sm font-medium text-gray-900">{{ $admin->name }}</div>
<div class="text-xs {{ $admin->email_verified_at ? 'text-green-500' : 'text-gray-500' }}">
{{ $admin->email_verified_at ? 'Active' : 'Inactive' }}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
ahmad.wijaya@example.com
{{ $admin->email }}
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-3 py-1 inline-flex text-xs leading-5 font-semibold rounded-full bg-purple-100 text-purple-800">
Super Admin
@php
$roleClass = [
'admin' => 'bg-blue-100 text-blue-800'
];
$roleLabel = [
'admin' => 'Admin'
];
@endphp
<span class="px-3 py-1 inline-flex text-xs leading-5 font-semibold rounded-full {{ $roleClass[$admin->role] ?? 'bg-gray-100 text-gray-800' }}">
{{ $roleLabel[$admin->role] ?? ucfirst($admin->role) }}
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button class="btn-action text-blue-600 hover:text-blue-900 mr-3 transition-colors">
<button class="btn-action text-blue-600 hover:text-blue-900 mr-3 transition-colors cursor-pointer hover:bg-blue-50 p-2 rounded"
onclick="editAdmin({{ $admin->id }})"
title="Edit Admin">
<i class="fas fa-edit"></i>
</button>
<button class="btn-action text-red-600 hover:text-red-900 transition-colors">
<button class="btn-action text-red-600 hover:text-red-900 transition-colors cursor-pointer hover:bg-red-50 p-2 rounded"
onclick="deleteAdmin({{ $admin->id }})"
title="Hapus Admin">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
<!-- Admin Row 2 -->
<tr class="table-row">
<td class="px-6 py-4 whitespace-nowrap">
<img src="https://picsum.photos/seed/admin2/50/50.jpg"
alt="Admin"
class="w-12 h-12 rounded-full object-cover border-2 border-gray-200">
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">Siti Nurhaliza</div>
<div class="text-xs text-gray-500">Active</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
siti.nurhaliza@example.com
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-3 py-1 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800">
Admin
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button class="btn-action text-blue-600 hover:text-blue-900 mr-3 transition-colors">
<i class="fas fa-edit"></i>
</button>
<button class="btn-action text-red-600 hover:text-red-900 transition-colors">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
<!-- Admin Row 3 -->
<tr class="table-row">
<td class="px-6 py-4 whitespace-nowrap">
<img src="https://picsum.photos/seed/admin3/50/50.jpg"
alt="Admin"
class="w-12 h-12 rounded-full object-cover border-2 border-gray-200">
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">Budi Santoso</div>
<div class="text-xs text-gray-500">Active</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
budi.santoso@example.com
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-3 py-1 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800">
Admin
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button class="btn-action text-blue-600 hover:text-blue-900 mr-3 transition-colors">
<i class="fas fa-edit"></i>
</button>
<button class="btn-action text-red-600 hover:text-red-900 transition-colors">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
<!-- Admin Row 4 -->
<tr class="table-row">
<td class="px-6 py-4 whitespace-nowrap">
<img src="https://picsum.photos/seed/admin4/50/50.jpg"
alt="Admin"
class="w-12 h-12 rounded-full object-cover border-2 border-gray-200">
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">Dewi Lestari</div>
<div class="text-xs text-gray-500">Inactive</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
dewi.lestari@example.com
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-3 py-1 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-100 text-blue-800">
Admin
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button class="btn-action text-blue-600 hover:text-blue-900 mr-3 transition-colors">
<i class="fas fa-edit"></i>
</button>
<button class="btn-action text-red-600 hover:text-red-900 transition-colors">
<i class="fas fa-trash"></i>
</button>
</td>
</tr>
<!-- Admin Row 5 -->
<tr class="table-row">
<td class="px-6 py-4 whitespace-nowrap">
<img src="https://picsum.photos/seed/admin5/50/50.jpg"
alt="Admin"
class="w-12 h-12 rounded-full object-cover border-2 border-gray-200">
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">Rizki Pratama</div>
<div class="text-xs text-gray-500">Active</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
rizki.pratama@example.com
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-3 py-1 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">
Moderator
</span>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button class="btn-action text-blue-600 hover:text-blue-900 mr-3 transition-colors">
<i class="fas fa-edit"></i>
</button>
<button class="btn-action text-red-600 hover:text-red-900 transition-colors">
<i class="fas fa-trash"></i>
</button>
@empty
<tr>
<td colspan="4" class="px-6 py-8 text-center text-gray-500">
<div class="flex flex-col items-center">
<i class="fas fa-users text-4xl mb-2 text-gray-300"></i>
<span>Belum ada data admin</span>
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@ -194,33 +94,237 @@ class="w-12 h-12 rounded-full object-cover border-2 border-gray-200">
@endsection
@section('scripts')
<style>
.btn-action {
transition: all 0.2s ease;
transform: scale(1);
}
.btn-action:hover {
transform: scale(1.1);
}
.btn-action:active {
transform: scale(0.95);
}
</style>
<!-- Add Admin Modal -->
<div id="adminModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50 flex items-center justify-center">
<div class="bg-white rounded-xl p-6 w-full max-w-md mx-4">
<div class="flex justify-between items-center mb-4">
<h3 id="modalTitle" class="text-xl font-semibold text-gray-900">Tambah Admin</h3>
<button onclick="closeModal()" class="text-gray-400 hover:text-gray-600">
<i class="fas fa-times"></i>
</button>
</div>
<form id="adminForm" onsubmit="saveAdmin(event)">
@csrf
<input type="hidden" id="adminId" name="id">
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">Nama</label>
<input type="text" id="name" name="name" required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">Email</label>
<input type="email" id="email" name="email" required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">Password</label>
<input type="password" id="password" name="password"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500">
</div>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">Role</label>
<select id="role" name="role" required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-red-500">
<option value="admin">Admin</option>
</select>
</div>
<div class="flex justify-end space-x-3">
<button type="button" onclick="closeModal()"
class="px-4 py-2 text-gray-700 bg-gray-200 rounded-lg hover:bg-gray-300 transition-colors">
Batal
</button>
<button type="submit" onclick="console.log('Submit button clicked');"
class="px-4 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition-colors">
Simpan
</button>
</div>
</form>
</div>
</div>
<script>
let currentEditId = null;
// Add Admin Modal functionality
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM loaded, setting up admin modal...');
const addAdminBtn = document.querySelector('.btn-primary');
const adminForm = document.getElementById('adminForm');
if (addAdminBtn) {
console.log('Add admin button found');
addAdminBtn.addEventListener('click', function() {
// In a real application, this would open a modal
alert('Modal tambah admin akan dibuka di sini');
console.log('Add admin button clicked');
openModal();
});
// Edit buttons
document.querySelectorAll('.btn-action.text-blue-600').forEach(btn => {
btn.addEventListener('click', function() {
// In a real application, this would open edit modal
alert('Modal edit admin akan dibuka di sini');
});
});
// Delete buttons
document.querySelectorAll('.btn-action.text-red-600').forEach(btn => {
btn.addEventListener('click', function() {
// In a real application, this would show confirmation dialog
if(confirm('Apakah Anda yakin ingin menghapus admin ini?')) {
alert('Admin akan dihapus');
} else {
console.error('Add admin button not found');
}
if (adminForm) {
console.log('Admin form found, setting up submit handler');
adminForm.addEventListener('submit', function(e) {
console.log('Form submit event triggered');
saveAdmin(e);
});
} else {
console.error('Admin form not found');
}
// Setup action buttons
const editButtons = document.querySelectorAll('[onclick*="editAdmin"]');
const deleteButtons = document.querySelectorAll('[onclick*="deleteAdmin"]');
console.log('Action buttons found:', {
edit: editButtons.length,
delete: deleteButtons.length
});
});
function openModal(adminId = null) {
const modal = document.getElementById('adminModal');
const form = document.getElementById('adminForm');
const title = document.getElementById('modalTitle');
form.reset();
document.getElementById('adminId').value = adminId || '';
if (adminId) {
title.textContent = 'Edit Admin';
// Load admin data
fetch(`/admin/manage-admin/${adminId}/edit`)
.then(response => response.json())
.then(data => {
document.getElementById('name').value = data.name;
document.getElementById('email').value = data.email;
document.getElementById('role').value = data.role;
document.getElementById('password').removeAttribute('required');
})
.catch(error => {
console.error('Error:', error);
alert('Gagal memuat data admin');
});
} else {
title.textContent = 'Tambah Admin';
document.getElementById('password').setAttribute('required', 'required');
}
modal.classList.remove('hidden');
}
function closeModal() {
document.getElementById('adminModal').classList.add('hidden');
document.getElementById('adminForm').reset();
}
function saveAdmin(event) {
event.preventDefault();
const formData = new FormData(event.target);
const adminId = formData.get('id');
const submitBtn = event.target.querySelector('button[type="submit"]');
// Show loading state
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>Menyimpan...';
submitBtn.disabled = true;
const url = adminId ? `/admin/manage-admin/${adminId}` : '/admin/manage-admin';
const method = adminId ? 'PUT' : 'POST';
// Convert FormData to object for JSON
const data = Object.fromEntries(formData.entries());
console.log('Data being sent:', data); // Debug log
delete data.id; // Remove id from data
fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify(data)
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
if (data.errors) {
// Handle validation errors
let errorMessages = '';
for (const field in data.errors) {
errorMessages += data.errors[field].join('\n') + '\n';
}
alert('Validation Error:\n' + errorMessages);
} else {
alert(data.success || 'Admin berhasil disimpan!');
closeModal();
location.reload(); // Reload to show updated data
}
})
.catch(error => {
console.error('Error:', error);
alert('Terjadi kesalahan. Silakan coba lagi.\nError: ' + error.message);
})
.finally(() => {
// Reset button state
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
});
}
function editAdmin(id) {
console.log('Edit admin clicked for ID:', id);
openModal(id);
}
function deleteAdmin(id) {
console.log('Delete admin clicked for ID:', id);
if (confirm('Apakah Anda yakin ingin menghapus admin ini?')) {
fetch(`/admin/manage-admin/${id}`, {
method: 'DELETE',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
}
})
.then(response => response.json())
.then(data => {
if (data.error) {
alert(data.error);
} else {
location.reload();
}
})
.catch(error => {
console.error('Error:', error);
alert('Terjadi kesalahan. Silakan coba lagi.');
});
}
}
</script>
@endsection

View File

@ -13,25 +13,25 @@
<!-- Navigation Menu -->
<nav class="flex-1 p-4 space-y-2">
<a href="{{ route('admin.dashboard') }}"
class="sidebar-item flex items-center space-x-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-50 transition-all {{ request()->routeIs('admin.dashboard') ? 'active' : '' }}">
class="sidebar-link flex items-center space-x-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-50 transition-all {{ request()->routeIs('admin.dashboard') ? 'active' : '' }}">
<i class="fas fa-home w-5"></i>
<span>Dashboard</span>
</a>
<a href="{{ route('admin.manage-admin') }}"
class="sidebar-item flex items-center space-x-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-50 transition-all {{ request()->routeIs('admin.manage-admin') ? 'active' : '' }}">
class="sidebar-link flex items-center space-x-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-50 transition-all {{ request()->routeIs('admin.manage-admin') ? 'active' : '' }}">
<i class="fas fa-users w-5"></i>
<span>Kelola Akun Admin</span>
</a>
<a href="{{ route('admin.classification-history') }}"
class="sidebar-item flex items-center space-x-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-50 transition-all {{ request()->routeIs('admin.classification-history') ? 'active' : '' }}">
class="sidebar-link flex items-center space-x-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-50 transition-all {{ request()->routeIs('admin.classification-history') ? 'active' : '' }}">
<i class="fas fa-history w-5"></i>
<span>Riwayat Klasifikasi</span>
</a>
<a href="{{ route('admin.system-statistics') }}"
class="sidebar-item flex items-center space-x-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-50 transition-all {{ request()->routeIs('admin.system-statistics') ? 'active' : '' }}">
class="sidebar-link flex items-center space-x-3 px-4 py-3 rounded-lg text-gray-700 hover:bg-gray-50 transition-all {{ request()->routeIs('admin.system-statistics') ? 'active' : '' }}">
<i class="fas fa-chart-bar w-5"></i>
<span>Statistik Sistem</span>
</a>

View File

@ -22,15 +22,15 @@
<div class="flex justify-between items-center h-16">
<div class="flex items-center">
<div class="flex-shrink-0">
<span class="text-2xl font-bold text-red-600">🍅 MaturityScan</span>
<span class="text-2xl font-bold text-red-600">MaturityScan</span>
</div>
</div>
<div class="hidden md:block">
<div class="ml-10 flex items-baseline space-x-4">
<a href="#" class="text-gray-900 hover:text-red-600 px-3 py-2 rounded-md text-sm font-medium transition-colors">Beranda</a>
<a href="{{ route('about') }}"class="text-gray-500 hover:text-red-600 px-3 py-2 rounded-md text-sm font-medium transition-colors">Tentang kami</a>
<a href="{{ route('login') }}" class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-md text-sm font-medium transition-colors">
<i class="fas fa-sign-in-alt mr-2"></i>Login
<a href="{{ route('login') }}" class="bg-red-600 hover:bg-red-700 text-white font-semibold py-2 px-6 rounded-lg transition-colors">
Login
</a>
</div>
</div>
@ -58,7 +58,7 @@
</p>
<div class="flex flex-col sm:flex-row gap-4 justify-center lg:justify-start">
<a href="{{ route('upload.index') }}" class="bg-red-600 hover:bg-red-700 text-white font-semibold py-3 px-8 rounded-lg shadow-lg transform hover:scale-105 transition-all duration-200 inline-block text-center">
📤 Unggah Gambar Tomat
Unggah Gambar Tomat
</a>
<a href="{{ route('about') }}" class="bg-white hover:bg-gray-50 text-gray-700 font-semibold py-3 px-8 rounded-lg shadow-md border border-gray-200 transition-all duration-200 inline-block text-center">
Pelajari Lebih Lanjut
@ -72,7 +72,7 @@
class="rounded-lg shadow-md w-full h-auto">
</div>
<div class="absolute -bottom-4 -right-4 bg-yellow-400 text-yellow-900 px-4 py-2 rounded-full font-semibold text-sm shadow-lg">
🌟 Akurasi 95%
<i class="fas fa-star mr-2"></i>Akurasi 95%
</div>
</div>
</div>
@ -90,7 +90,7 @@ class="rounded-lg shadow-md w-full h-auto">
<!-- Mentah Card -->
<div class="bg-green-50 border-2 border-green-200 rounded-xl p-8 text-center hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2">
<div class="w-20 h-20 bg-green-500 rounded-full mx-auto mb-6 flex items-center justify-center">
<span class="text-3xl">🍃</span>
<i class="fas fa-leaf text-3xl text-green-200"></i>
</div>
<h3 class="text-2xl font-bold text-green-800 mb-4">Mentah</h3>
<p class="text-gray-600 mb-4">Tomat yang belum matang sempurna, berwarna hijau dan tekstur masih keras.</p>
@ -102,7 +102,7 @@ class="rounded-lg shadow-md w-full h-auto">
<!-- Setengah Matang Card -->
<div class="bg-yellow-50 border-2 border-yellow-200 rounded-xl p-8 text-center hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2">
<div class="w-20 h-20 bg-yellow-500 rounded-full mx-auto mb-6 flex items-center justify-center">
<span class="text-3xl">🟡</span>
<i class="fas fa-circle-half-stroke text-3xl text-yellow-200"></i>
</div>
<h3 class="text-2xl font-bold text-yellow-800 mb-4">Setengah Matang</h3>
<p class="text-gray-600 mb-4">Tomat dalam proses pematangan, perpaduan warna hijau dan merah.</p>
@ -114,7 +114,7 @@ class="rounded-lg shadow-md w-full h-auto">
<!-- Matang Card -->
<div class="bg-red-50 border-2 border-red-200 rounded-xl p-8 text-center hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2">
<div class="w-20 h-20 bg-red-500 rounded-full mx-auto mb-6 flex items-center justify-center">
<span class="text-3xl">🍅</span>
<i class="fas fa-circle text-3xl text-red-200"></i>
</div>
<h3 class="text-2xl font-bold text-red-800 mb-4">Matang</h3>
<p class="text-gray-600 mb-4">Tomat matang sempurna, berwarna merah cerah dan tekstur lembut.</p>
@ -138,7 +138,7 @@ class="rounded-lg shadow-md w-full h-auto">
<div class="relative">
<div class="bg-white rounded-xl p-8 shadow-lg hover:shadow-2xl transition-all duration-300 text-center">
<div class="w-16 h-16 bg-blue-500 rounded-full mx-auto mb-6 flex items-center justify-center">
<span class="text-2xl">📷</span>
<i class="fas fa-camera text-2xl text-white"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 mb-4">Unggah Gambar</h3>
<p class="text-gray-600">Ambil foto tomat atau unggah gambar dari galeri perangkat Anda.</p>
@ -154,7 +154,7 @@ class="rounded-lg shadow-md w-full h-auto">
<div class="relative">
<div class="bg-white rounded-xl p-8 shadow-lg hover:shadow-2xl transition-all duration-300 text-center">
<div class="w-16 h-16 bg-purple-500 rounded-full mx-auto mb-6 flex items-center justify-center">
<span class="text-2xl">🤖</span>
<i class="fas fa-robot text-2xl text-white"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 mb-4">Analisis AI</h3>
<p class="text-gray-600">Sistem AI kami menganalisis warna, tekstur, dan bentuk tomat secara otomatis.</p>
@ -170,7 +170,7 @@ class="rounded-lg shadow-md w-full h-auto">
<div class="relative">
<div class="bg-white rounded-xl p-8 shadow-lg hover:shadow-2xl transition-all duration-300 text-center">
<div class="w-16 h-16 bg-green-500 rounded-full mx-auto mb-6 flex items-center justify-center">
<span class="text-2xl">📊</span>
<i class="fas fa-chart-line text-2xl text-white"></i>
</div>
<h3 class="text-xl font-bold text-gray-900 mb-4">Dapatkan Hasil</h3>
<p class="text-gray-600">Lihat hasil klasifikasi kematangan tomat dengan akurasi tinggi.</p>
@ -208,16 +208,16 @@ class="rounded-lg shadow-md w-full h-auto">
<h3 class="text-lg font-semibold mb-4">Connect</h3>
<div class="flex space-x-4">
<a href="#" class="w-10 h-10 bg-gray-800 rounded-full flex items-center justify-center hover:bg-gray-700 transition-colors">
<span class="text-lg">📘</span>
<i class="fab fa-facebook-f text-lg"></i>
</a>
<a href="#" class="w-10 h-10 bg-gray-800 rounded-full flex items-center justify-center hover:bg-gray-700 transition-colors">
<span class="text-lg">🐦</span>
<i class="fab fa-twitter text-lg"></i>
</a>
<a href="#" class="w-10 h-10 bg-gray-800 rounded-full flex items-center justify-center hover:bg-gray-700 transition-colors">
<span class="text-lg">📷</span>
<i class="fab fa-instagram text-lg"></i>
</a>
<a href="#" class="w-10 h-10 bg-gray-800 rounded-full flex items-center justify-center hover:bg-gray-700 transition-colors">
<span class="text-lg">💼</span>
<i class="fab fa-linkedin-in text-lg"></i>
</a>
</div>
<div class="mt-4">

View File

@ -2,6 +2,7 @@
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UploadController;
use App\Http\Controllers\AdminController;
Route::get('/', function () {
return view('welcome');
@ -37,13 +38,13 @@
return view('Admin.index');
})->name('admin.dashboard');
// Manage admin route
Route::get('/admin/manage-admin', function () {
if (!session('admin_logged_in')) {
return redirect()->route('admin.login')->with('error', 'Silakan login terlebih dahulu.');
}
return view('Admin.manage-admin');
})->name('admin.manage-admin');
// Manage admin routes
Route::get('/admin/manage-admin', [AdminController::class, 'index'])->name('admin.manage-admin');
Route::post('/admin/manage-admin', [AdminController::class, 'store'])->name('admin.manage-admin.store');
Route::get('/admin/manage-admin/{id}/edit', [AdminController::class, 'edit'])->name('admin.manage-admin.edit');
Route::put('/admin/manage-admin/{id}', [AdminController::class, 'update'])->name('admin.manage-admin.update');
Route::delete('/admin/manage-admin/{id}', [AdminController::class, 'destroy'])->name('admin.manage-admin.destroy');
Route::patch('/admin/manage-admin/{id}/toggle-status', [AdminController::class, 'toggleStatus'])->name('admin.manage-admin.toggle-status');
// Classification history route
Route::get('/admin/classification-history', function () {