MIF_E31222313/resources/views/admin/dashboard.blade.php

630 lines
18 KiB
PHP

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Admin Dashboard</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no" />
<meta name="csrf-token" content="{{ csrf_token() }}">
<!-- Fonts and icons -->
<script src="{{ asset('admin/js/plugin/webfont/webfont.min.js') }}"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" />
<script>
WebFont.load({
google: { families: ["Lato:300,400,700,900"] },
custom: {
families: [
"Font Awesome 5 Solid",
"Font Awesome 5 Regular",
"Font Awesome 5 Brands",
"simple-line-icons",
],
urls: ['../assets/css/fonts.min.css'],
},
active: function () {
sessionStorage.fonts = true;
},
});
</script>
<!-- CSS Files -->
<link rel="stylesheet" href="{{ asset('admin/css/bootstrap.min.css') }}" />
<link rel="stylesheet" href="{{ asset('admin/css/atlantis.css') }}" />
<style>
body, html {
margin: 0;
padding: 0;
height: 100%;
background: #f8fafc;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
/* Bagian atas dengan background gradient dan teks */
.gradient-container {
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #a855f7 100%);
color: white;
padding: 3.5rem 2rem 3rem;
position: relative;
box-sizing: border-box;
min-height: 280px;
overflow: hidden;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
box-shadow: 0 5px 15px rgba(107, 33, 168, 0.3);
}
.gradient-container::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: radial-gradient(circle at 30% 20%, rgba(255,255,255,0.1) 0%, transparent 70%);
pointer-events: none;
z-index: 1;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
}
.gradient-container h2,
.gradient-container h5 {
position: relative;
z-index: 2;
margin: 0;
max-width: 680px;
line-height: 1.4;
user-select: none;
}
.gradient-container h2 {
font-size: 1.7rem;
font-weight: 700;
margin-bottom: 1.3rem;
letter-spacing: -0.025em;
}
.gradient-container h5 {
font-size: 1rem;
font-weight: 400;
opacity: 0.95;
}
/* Container card, margin negatif agar card "menempel" */
.card-container {
position: relative;
z-index: 10;
margin-top: -80px;
padding: 0 2rem 3rem;
max-width: 1200px;
margin-left: auto;
margin-right: auto;
box-sizing: border-box;
}
/* Styling card */
.card {
background: white;
border-radius: 16px;
box-shadow: 0 10px 30px rgba(0,0,0,0.08), 0 4px 10px rgba(0,0,0,0.04);
padding: 2rem;
margin-bottom: 1.5rem;
border: none;
position: relative;
overflow: hidden;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
align-items: center;
gap: 1.5rem;
}
.card::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0;
height: 4px;
border-top-left-radius: 16px;
border-top-right-radius: 16px;
}
.card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 40px rgba(0,0,0,0.12), 0 8px 16px rgba(0,0,0,0.08);
}
/* Icon besar di card */
.icon-big {
font-size: 2.5rem;
width: 70px;
height: 70px;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
color: white;
box-shadow: 0 8px 20px rgba(0,0,0,0.1);
flex-shrink: 0;
}
/* Custom gradient backgrounds for icons */
.visitors-icon {
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
box-shadow: 0 8px 20px rgba(59, 130, 246, 0.4);
}
.subscribers-icon {
background: linear-gradient(135deg, #10b981, #047857);
box-shadow: 0 8px 20px rgba(16, 185, 129, 0.4);
}
.sales-icon {
background: linear-gradient(135deg, #f59e0b, #d97706);
box-shadow: 0 8px 20px rgba(245, 158, 11, 0.4);
}
.orders-icon {
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
box-shadow: 0 8px 20px rgba(139, 92, 246, 0.4);
}
/* Quiz control specific icon */
.quiz-control-icon {
background: linear-gradient(135deg, #ec4899, #be185d);
box-shadow: 0 8px 20px rgba(236, 72, 153, 0.4);
}
/* Card text info tanpa background, hanya warna teks */
.card-info {
flex: 1;
min-width: 0;
background: none !important;
}
/* PAKSA warna teks kategori dan judul agar override */
.card-info p.card-category {
font-size: 0.7rem;
margin-bottom: 0.5rem;
text-transform: uppercase;
font-weight: 600;
letter-spacing: 0.08em;
user-select: none;
color: #64748b !important;
}
.card-info h4.card-title {
font-size: 1.5rem;
font-weight: 700;
margin: 0;
line-height: 1.2;
user-select: none;
color: #1e293b !important;
}
/* Stats trend indicator */
.stats-trend {
margin-top: 0.75rem;
font-size: 0.85rem;
display: flex;
align-items: center;
gap: 0.3rem;
user-select: none;
}
.trend-up {
color: #059669;
}
.trend-down {
color: #dc2626;
}
/* Quiz control card styling */
.quiz-control-card {
background: linear-gradient(135deg, #fef7ff 0%, #f3e8ff 100%);
border: 2px solid #e879f9;
margin-top: 2rem;
padding: 2rem;
border-radius: 16px;
box-shadow: 0 10px 30px rgba(232, 121, 249, 0.15);
text-align: center;
}
.quiz-control-card:hover {
transform: translateY(-6px);
box-shadow: 0 20px 60px rgba(232, 121, 249, 0.25);
}
.quiz-status-badge {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
border-radius: 12px;
font-weight: 600;
font-size: 0.875rem;
margin-bottom: 1rem;
}
.quiz-status-open {
background: linear-gradient(135deg, #dcfce7, #bbf7d0);
color: #166534;
border: 1px solid #86efac;
}
.quiz-status-closed {
background: linear-gradient(135deg, #fee2e2, #fecaca);
color: #991b1b;
border: 1px solid #f87171;
}
.quiz-toggle-btn {
padding: 0.75rem 1.5rem;
border-radius: 12px;
border: none;
font-weight: 600;
font-size: 0.875rem;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.quiz-toggle-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.btn-open-quiz {
background: linear-gradient(135deg, #10b981, #059669);
color: white;
box-shadow: 0 6px 20px rgba(16, 185, 129, 0.3);
}
.btn-open-quiz:hover:not(:disabled) {
background: linear-gradient(135deg, #059669, #047857);
transform: translateY(-3px);
box-shadow: 0 12px 30px rgba(16, 185, 129, 0.4);
}
.btn-close-quiz {
background: linear-gradient(135deg, #f59e0b, #d97706);
color: white;
box-shadow: 0 6px 20px rgba(245, 158, 11, 0.3);
}
.btn-close-quiz:hover:not(:disabled) {
background: linear-gradient(135deg, #d97706, #b45309);
transform: translateY(-3px);
box-shadow: 0 12px 30px rgba(245, 158, 11, 0.4);
}
/* Responsive improvements */
@media (max-width: 991px) {
.gradient-container {
padding: 3rem 1.5rem 2.5rem;
min-height: 280px;
border-radius: 0 0 20px 20px;
}
.gradient-container h2 {
font-size: 1.8rem;
}
.gradient-container h5 {
font-size: 1rem;
}
.card-container {
padding: 0 1.5rem 3rem;
margin-top: -80px;
}
.card {
padding: 2rem;
gap: 1.5rem;
}
.icon-big {
width: 70px;
height: 70px;
font-size: 2.25rem;
}
.card-info h4.card-title {
font-size: 1.5rem !important;
}
.quiz-control-card {
padding: 2.5rem;
}
}
@media (max-width: 575px) {
.card {
flex-direction: column;
align-items: center;
text-align: center;
gap: 1.5rem;
}
.quiz-toggle-btn {
min-width: 160px;
padding: 0.875rem 1.5rem;
}
}
/* Animation */
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(40px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card {
animation: slideInUp 0.8s ease forwards;
opacity: 0;
}
.card:nth-child(1) { animation-delay: 0.1s; }
.card:nth-child(2) { animation-delay: 0.2s; }
.card:nth-child(3) { animation-delay: 0.3s; }
.card:nth-child(4) { animation-delay: 0.4s; }
.card:nth-child(5) { animation-delay: 0.5s; }
</style>
</head>
<body>
<div class="wrapper">
<div class="main-header">
<!-- Logo Header -->
<div class="logo-header" data-background-color="blue">
<div class="nav-toggle">
<button class="btn btn-toggle toggle-sidebar">
<i class="fas fa-bars"></i>
</button>
</div>
</div>
<!-- End Logo Header -->
<!-- Navbar Header -->
@include('admin.navbar')
<!-- End Navbar -->
</div>
<!-- Sidebar -->
@include('admin.sidebar')
<!-- End Sidebar -->
<div class="main-panel">
<div class="content">
<!-- Bagian atas dengan gradient dan teks -->
<div class="gradient-container">
<h2 class="fw-bold">
Selamat datang kembali, {{ Auth::user()->name }}! 👋
</h2>
<h5>
Ini adalah pusat kendali sistem pendukung keputusan. Pantau data terbaru dan kelola informasi siswa dengan lebih terstruktur dan mudah diakses.
</h5>
</div>
<!-- Container card -->
<div class="card-container container">
<div class="row g-4">
<!-- Card 1: Total Siswa -->
<div class="col-12 col-sm-6 col-md-3">
<a href="{{ route('siswa') }}" class="text-decoration-none">
<div class="card clickable-card" style="animation-fill-mode: forwards;">
<div class="icon-big visitors-icon">
<i class="fa-solid fa-users"></i>
</div>
<div class="card-info">
<p class="card-category">Total Siswa</p>
<h4 class="card-title">{{ number_format($totalSiswa) }}</h4>
</div>
</div>
</a>
</div>
<!-- Card 2: Kurikulum -->
<div class="col-12 col-sm-6 col-md-3">
<a href="{{ route('kurikulum') }}" class="text-decoration-none">
<div class="card clickable-card" style="animation-fill-mode: forwards;">
<div class="icon-big subscribers-icon">
<i class="fa-solid fa-book-open-reader"></i>
</div>
<div class="card-info">
<p class="card-category">Kurikulum</p>
<h4 class="card-title">{{ number_format($totalKurikulum) }}</h4>
</div>
</div>
</a>
</div>
<!-- Card 3: Total Responden -->
<div class="col-12 col-sm-6 col-md-3">
<a href="{{ route('perhitungan') }}" class="text-decoration-none">
<div class="card clickable-card" style="animation-fill-mode: forwards;">
<div class="icon-big sales-icon">
<i class="fa-solid fa-chart-line"></i>
</div>
<div class="card-info">
<p class="card-category">Total Responden</p>
<h4 class="card-title">{{ number_format($totalResponden) }}</h4>
</div>
</div>
</a>
</div>
<!-- Card 4: Sekolah -->
<div class="col-12 col-sm-6 col-md-3">
<a href="{{ route('sekolah') }}" class="text-decoration-none">
<div class="card clickable-card" style="animation-fill-mode: forwards;">
<div class="icon-big orders-icon">
<i class="fa-solid fa-school"></i>
</div>
<div class="card-info">
<p class="card-category">Sekolah</p>
<h4 class="card-title">{{ number_format($totalSekolah) }}</h4>
</div>
</div>
</a>
</div>
</div> <!-- end row -->
<!-- Quiz Control Section -->
<div class="row mt-4">
<div class="col-12">
<div class="card quiz-control-card" style="animation-fill-mode: forwards;">
<div class="icon-big quiz-control-icon">
<i class="fa-solid fa-shield-halved"></i>
</div>
<div class="card-info">
<p class="card-category">Kontrol Akses Quiz</p>
<h4 class="card-title">Kelola Akses User ke Section Quiz</h4>
<div class="mt-3">
<div class="quiz-status-badge {{ $quizAccessStatus ? 'quiz-status-open' : 'quiz-status-closed' }}" id="statusBadge">
<i class="fa-solid {{ $quizAccessStatus ? 'fa-lock-open' : 'fa-lock' }}"></i>
<span id="statusText">{{ $quizAccessStatus ? 'QUIZ TERBUKA' : 'QUIZ TERKUNCI' }}</span>
</div>
<div class="mt-3">
<button
id="toggleQuizBtn"
class="quiz-toggle-btn {{ $quizAccessStatus ? 'btn-close-quiz' : 'btn-open-quiz' }}"
onclick="toggleQuizAccess()"
>
<i class="fa-solid {{ $quizAccessStatus ? 'fa-lock' : 'fa-lock-open' }}"></i>
<span id="btnText">{{ $quizAccessStatus ? 'Tutup Akses Quiz' : 'Buka Akses Quiz' }}</span>
</button>
</div>
<small class="text-muted mt-2 d-block" id="statusDescription">
{{ $quizAccessStatus
? 'Semua user dapat mengakses section quiz di dashboard mereka'
: 'Section quiz terkunci untuk semua user hingga Anda membuka akses'
}}
</small>
</div>
</div>
</div>
</div>
</div>
</div> <!-- end card-container -->
</div> <!-- end content -->
</div> <!-- end main-panel -->
</div> <!-- end wrapper -->
<!-- Script Files -->
@include('admin.script')
<!-- End Script Files -->
<script>
// Set up CSRF token for AJAX requests
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
// Animate numbers on page load
document.addEventListener('DOMContentLoaded', function() {
const cardTitles = document.querySelectorAll('.card-title');
cardTitles.forEach((title, index) => {
const finalText = title.textContent.trim();
const numericValue = parseInt(finalText.replace(/[^0-9]/g, ''));
if (!isNaN(numericValue) && numericValue > 0) {
let currentValue = 0;
const increment = Math.max(1, numericValue / 60);
const hasSymbol = finalText.includes('$');
const timer = setInterval(() => {
currentValue += increment;
if (currentValue >= numericValue) {
title.textContent = finalText;
clearInterval(timer);
} else {
const displayValue = Math.floor(currentValue).toLocaleString();
title.textContent = hasSymbol ? `$ ${displayValue}` : displayValue;
}
}, 25 + (index * 8));
} else {
// Jika bukan angka valid, tetap tampilkan teks asli
title.textContent = finalText;
}
});
});
// Function to toggle quiz access
function toggleQuizAccess() {
const btn = document.getElementById('toggleQuizBtn');
const btnText = document.getElementById('btnText');
const statusBadge = document.getElementById('statusBadge');
const statusText = document.getElementById('statusText');
const statusDescription = document.getElementById('statusDescription');
// Disable button during request
btn.disabled = true;
btnText.textContent = 'Memproses...';
// Make AJAX request
fetch('{{ route("admin.toggle-quiz-access") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Update UI based on new status
const isOpen = data.status;
// Update button
btn.className = `quiz-toggle-btn ${isOpen ? 'btn-close-quiz' : 'btn-open-quiz'}`;
btn.querySelector('i').className = `fa-solid ${isOpen ? 'fa-lock' : 'fa-lock-open'}`;
btnText.textContent = isOpen ? 'Tutup Akses Quiz' : 'Buka Akses Quiz';
// Update status badge
statusBadge.className = `quiz-status-badge ${isOpen ? 'quiz-status-open' : 'quiz-status-closed'}`;
statusBadge.querySelector('i').className = `fa-solid ${isOpen ? 'fa-lock-open' : 'fa-lock'}`;
statusText.textContent = isOpen ? 'QUIZ TERBUKA' : 'QUIZ TERKUNCI';
// Update description
statusDescription.textContent = isOpen
? 'Semua user dapat mengakses section quiz di dashboard mereka'
: 'Section quiz terkunci untuk semua user hingga Anda membuka akses';
// Show success message using toastr
toastr.success(data.message);
} else {
// Show error message using toastr
toastr.error(data.message || 'Terjadi kesalahan');
}
})
.catch(error => {
console.error('Error:', error);
// Show error message using toastr
toastr.error('Terjadi kesalahan saat memproses permintaan');
})
.finally(() => {
// Re-enable button
btn.disabled = false;
});
}
</script>
</body>
</html>