MIF_E31230356/resources/views/siswa/dashboard.blade.php

526 lines
14 KiB
PHP

@extends('siswa.layouts.app')
@section('title', 'Dashboard Siswa')
@push('styles')
<style>
.dashboard-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
@media (max-width: 768px) {
.dashboard-grid { grid-template-columns: 1fr; }
.dashboard-grid .lb-full { grid-column: 1; }
}
.dash-card {
background: #ffffff;
border-radius: 20px;
padding: 20px;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
flex-wrap: wrap;
gap: 8px;
}
.card-title {
font-size: 18px;
font-weight: 700;
color: #1e293b;
margin: 0;
}
.card-link {
font-size: 13px;
font-weight: 600;
color: #2b8ef3;
text-decoration: none;
}
.card-link:hover { text-decoration: underline; }
.icon-sm { width: 16px; height: 16px; object-fit: contain; vertical-align: middle; }
.icon-md { width: 24px; height: 24px; object-fit: contain; vertical-align: middle; }
.icon-rank { width: 28px; height: 28px; object-fit: contain; vertical-align: middle; }
.icon-mascot {
width: 220px;
max-width: 100%;
height: auto;
object-fit: contain;
margin-top: 24px;
}
/* TUGAS */
.tugas-date-label {
font-size: 13px;
font-weight: 600;
color: #64748b;
margin: 12px 0 8px;
}
.tugas-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 0;
border-bottom: 1px solid #f1f5f9;
}
.tugas-item:last-child { border-bottom: none; }
.tugas-time {
font-size: 12px;
color: #94a3b8;
font-weight: 500;
min-width: 36px;
flex-shrink: 0;
}
.tugas-info { flex: 1; min-width: 0; }
.tugas-nama {
font-size: 14px;
font-weight: 600;
color: #2b8ef3;
margin: 0 0 2px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.tugas-mapel {
font-size: 12px;
color: #94a3b8;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.tugas-empty {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
text-align: center;
color: #94a3b8;
font-size: 13px;
padding: 20px 0;
}
.tugas-link {
text-decoration: none;
color: inherit;
display: block;
}
/* KALENDER */
.calendar-nav {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.calendar-nav button {
background: none;
border: none;
font-size: 18px;
color: #64748b;
cursor: pointer;
padding: 4px 8px;
border-radius: 6px;
transition: background 0.2s;
}
.calendar-nav button:hover { background: #f1f5f9; }
.calendar-month {
font-size: 15px;
font-weight: 600;
color: #1e293b;
}
.calendar-table {
width: 100%;
border-collapse: collapse;
text-align: center;
table-layout: fixed;
}
.calendar-table th {
font-size: 10px;
font-weight: 600;
color: #94a3b8;
padding: 5px 0;
text-transform: uppercase;
letter-spacing: 0.03em;
}
.calendar-table td {
font-size: 13px;
color: #475569;
padding: 6px 0;
cursor: pointer;
transition: background 0.2s;
}
.calendar-table td:hover {
background: #e6f0ff;
color: #2b8ef3;
border-radius: 50%;
}
.calendar-table td.today {
background: #2b8ef3;
color: white;
border-radius: 50%;
font-weight: 700;
}
.calendar-table td.other-month { color: #cbd5e1; }
/* CHALLENGE */
.challenge-item {
display: flex;
align-items: center;
gap: 14px;
margin-bottom: 16px;
}
.challenge-bolt {
width: 44px;
height: 44px;
background: #fef9c3;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.challenge-desc {
font-size: 13px;
color: #64748b;
margin: 0 0 8px;
}
.progress-bar-wrap {
background: #f1f5f9;
border-radius: 99px;
height: 8px;
width: 100%;
overflow: hidden;
}
.progress-bar-fill {
height: 100%;
background: linear-gradient(90deg, #2b8ef3, #60a5fa);
border-radius: 99px;
transition: width 0.6s ease;
}
.progress-label {
font-size: 11px;
color: #94a3b8;
text-align: center;
margin-top: 4px;
}
.challenge-footer {
text-align: center;
margin-top: 12px;
}
/* MASCOT */
.mascot-card {
background: #fffbeb;
border-radius: 20px;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: 0 2px 12px rgba(0,0,0,0.06);
}
.speech-bubble {
background: #fde68a;
border-radius: 16px;
padding: 14px 18px;
font-size: 14px;
color: #78350f;
text-align: center;
line-height: 1.6;
position: relative;
width: 100%;
box-sizing: border-box;
word-break: break-word;
}
.speech-bubble::after {
content: '';
position: absolute;
bottom: -14px;
left: 50%;
transform: translateX(-50%);
border: 7px solid transparent;
border-top-color: #fde68a;
}
/* LEADERBOARD */
.lb-item {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 0;
border-bottom: 1px solid #f1f5f9;
}
.lb-item:last-child { border-bottom: none; }
.lb-rank-icon {
width: 32px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.lb-avatar {
width: 34px;
height: 34px;
border-radius: 50%;
background: linear-gradient(135deg, #2b8ef3, #60a5fa);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: 700;
font-size: 13px;
flex-shrink: 0;
}
.lb-name {
flex: 1;
font-size: 14px;
font-weight: 600;
color: #1e293b;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.lb-name.is-me { color: #2b8ef3; }
.lb-exp {
font-size: 13px;
font-weight: 600;
color: #64748b;
flex-shrink: 0;
}
</style>
@endpush
@section('content')
@php $namaSaya = Auth::guard('siswa')->user()->nama ?? ''; @endphp
<div class="dashboard-grid">
{{-- ===== TUGAS ===== --}}
<div class="dash-card">
<div class="card-header">
<h2 class="card-title">Tugas</h2>
<a href="{{ route('siswa.tugas.index') }}" class="card-link">LIHAT SEMUA</a>
</div>
@forelse($tugasList as $tanggal => $items)
<p class="tugas-date-label">{{ $tanggal }}</p>
@foreach($items as $item)
<a href="{{ route('siswa.tugas.show', $item['id_tugas']) }}" class="tugas-link">
<div class="tugas-item">
<span class="tugas-time">{{ $item['jam'] }}</span>
<img src="{{ asset('images/icon/siswadb/buku.png') }}" alt="Ikon tugas" class="icon-md" style="flex-shrink:0;">
<div class="tugas-info">
<p class="tugas-nama">{{ $item['nama'] }}</p>
<p class="tugas-mapel">{{ $item['mapel'] }}</p>
</div>
</div>
</a>
@endforeach
@empty
<div class="tugas-empty">
<img src="{{ asset('images/icon/siswadb/confetti.png') }}" alt="Semua tugas selesai" class="icon-sm">
Tidak ada tugas yang pending!
</div>
@endforelse
</div>
{{-- ===== KALENDER ===== --}}
<div class="dash-card">
<div class="calendar-nav">
<button id="prevMonth">&#8249;</button>
<span class="calendar-month" id="calMonthLabel"></span>
<button id="nextMonth">&#8250;</button>
</div>
<table class="calendar-table">
<thead>
<tr>
<th>SUN</th><th>MON</th><th>TUE</th>
<th>WED</th><th>THU</th><th>FRI</th><th>SAT</th>
</tr>
</thead>
<tbody id="calBody"></tbody>
</table>
</div>
{{-- ===== PROGRESS BAR ===== --}}
<div class="dash-card">
<div class="card-header">
<h2 class="card-title">Progress Tugas</h2>
</div>
@php
$persen = $tugasTotal > 0
? round(($tugasDikumpulkan / $tugasTotal) * 100)
: 0;
@endphp
<div class="challenge-item">
<div class="challenge-bolt">
<img src="{{ asset('images/icon/siswadb/starw.png') }}" alt="Ikon tugas" class="icon-md">
</div>
<div style="flex:1;min-width:0;">
<p class="challenge-desc">Selesaikan tugasmu sebelum deadline!</p>
<div class="progress-bar-wrap">
<div class="progress-bar-fill" style="width: {{ $persen }}%"></div>
</div>
<p class="progress-label">{{ $tugasDikumpulkan }}/{{ $tugasTotal }}</p>
</div>
</div>
<div class="challenge-footer">
<a href="{{ route('siswa.tugas.index') }}" class="card-link">LIHAT SEMUA</a>
</div>
</div>
{{-- ===== MASCOT + SPEECH BUBBLE ===== --}}
<div class="mascot-card">
<div class="speech-bubble">
@if($tugasSelesai > 0)
Kamu sudah mengerjakan <strong>{{ $tugasSelesai }} tugas</strong> minggu
ini, yuk lanjutkan untuk mendapatkan badge yang lebih menarik!
@else
Belum ada tugas yang diselesaikan minggu ini.
Ayo mulai kerjakan tugasmu!
<img src="{{ asset('images/icon/siswadb/muscle.png') }}" alt="Semangat!" class="icon-sm">
@endif
</div>
<img src="{{ asset('images/icon/mascot/mascot-hi.png') }}" alt="Maskot Belajar" class="icon-mascot">
</div>
{{-- ===== LEADERBOARD ===== --}}
<div class="dash-card lb-full" style="grid-column: 1 / -1;">
<div class="card-header">
<h2 class="card-title">Leaderboard</h2>
<a href="{{ route('siswa.leaderboard.index') }}" class="card-link">LIHAT SEMUA</a>
</div>
@forelse($leaderboard as $lb)
<div class="lb-item">
<span class="lb-rank-icon">
@if($lb['rank'] === 1)
<img src="{{ asset('images/icon/siswadb/1.png') }}" alt="Peringkat 1" class="icon-rank">
@elseif($lb['rank'] === 2)
<img src="{{ asset('images/icon/siswadb/2.png') }}" alt="Peringkat 2" class="icon-rank">
@else
<img src="{{ asset('images/icon/siswadb/3.png') }}" alt="Peringkat 3" class="icon-rank">
@endif
</span>
<div class="lb-avatar">{{ strtoupper(substr($lb['nama'], 0, 1)) }}</div>
<span class="lb-name {{ $lb['nama'] === $namaSaya ? 'is-me' : '' }}">
{{ $lb['nama'] }}
</span>
<span class="lb-exp">{{ number_format($lb['exp']) }} EXP</span>
</div>
@empty
<p style="color:#94a3b8;font-size:13px;text-align:center;padding:16px 0">
Belum ada data leaderboard.
</p>
@endforelse
</div>
</div>
@endsection
@push('scripts')
<script>
let currentDate = new Date();
function renderCalendar(date) {
const year = date.getFullYear();
const month = date.getMonth();
const monthNames = [
'January','February','March','April','May','June',
'July','August','September','October','November','December'
];
document.getElementById('calMonthLabel').textContent = monthNames[month] + ' ' + year;
const firstDay = new Date(year, month, 1).getDay();
const daysInMonth = new Date(year, month + 1, 0).getDate();
const prevDays = new Date(year, month, 0).getDate();
const today = new Date();
let html = '';
let dayCount = 1;
let extraDay = 1;
for (let row = 0; row < 6; row++) {
html += '<tr>';
for (let col = 0; col < 7; col++) {
const idx = row * 7 + col;
if (idx < firstDay) {
html += `<td class="other-month">${prevDays - firstDay + idx + 1}</td>`;
} else if (dayCount > daysInMonth) {
html += `<td class="other-month">${extraDay++}</td>`;
} else {
const isToday = (
dayCount === today.getDate() &&
month === today.getMonth() &&
year === today.getFullYear()
);
html += `<td class="${isToday ? 'today' : ''}">${dayCount}</td>`;
dayCount++;
}
}
html += '</tr>';
if (dayCount > daysInMonth && row >= 4) break;
}
document.getElementById('calBody').innerHTML = html;
}
document.getElementById('prevMonth').addEventListener('click', () => {
currentDate.setMonth(currentDate.getMonth() - 1);
renderCalendar(currentDate);
});
document.getElementById('nextMonth').addEventListener('click', () => {
currentDate.setMonth(currentDate.getMonth() + 1);
renderCalendar(currentDate);
});
renderCalendar(currentDate);
</script>
@endpush