fix: presensi - filter tanggal-kelas live, urutan tanggal di depan, pembersihan data yatim

This commit is contained in:
Novy San87
2026-08-02 20:57:14 +07:00
parent 6e256661dd
commit 58ffd06625
4 changed files with 137 additions and 29 deletions
+45 -18
View File
@@ -19,36 +19,36 @@
{{-- Pilih Kelas + Tanggal --}}
<div class="rounded-2xl bg-gradient-to-br from-white to-gray-50/80 border border-gray-200 shadow-sm mb-6 transition-all duration-200 hover:shadow-md">
<form method="GET" class="p-6">
<form method="GET" x-data="attendanceLink()" class="p-6">
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-1.5">
<i class="fa-solid fa-calendar text-gray-400 mr-1"></i> Tanggal <span class="text-red-500">*</span>
</label>
<input type="date" name="date" value="{{ $date }}" x-model="date" @change="refreshStatus($event)"
class="w-full px-4 py-2.5 border border-gray-200 rounded-xl text-sm bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition shadow-sm">
</div>
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-1.5">
<i class="fa-solid fa-school text-gray-400 mr-1"></i> Kelas <span class="text-red-500">*</span>
</label>
<select name="class_name" required
<select name="class_name" required x-model="sel"
class="w-full px-4 py-2.5 border border-gray-200 rounded-xl text-sm bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition shadow-sm">
<option value="">Pilih kelas...</option>
@foreach($classNames as $cn)
@php
$stat = $classAttendanceStatus[$cn] ?? ['has_data' => false, 'recorded' => 0, 'total' => 0];
$label = $stat['has_data']
? '✅ ' . $cn . ' (' . $stat['recorded'] . '/' . $stat['total'] . ')'
: '⬜ ' . $cn;
@endphp
<option value="{{ $cn }}" @selected($className == $cn)>{{ $label }}</option>
@endforeach
<template x-for="cn in classList" :key="cn">
<option :value="cn" x-text="label(cn)"></option>
</template>
</select>
<div class="mt-1.5 flex items-center gap-3 text-[10px] text-gray-400">
<span class="inline-flex items-center gap-1"><span class="w-2 h-2 rounded-sm bg-gray-300"></span> Belum</span>
<span class="inline-flex items-center gap-1"><span class="w-2 h-2 rounded-sm bg-emerald-400"></span> Terisi</span>
</div>
</div>
<div>
<label class="block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-1.5">
<i class="fa-solid fa-calendar text-gray-400 mr-1"></i> Tanggal <span class="text-red-500">*</span>
</label>
<input type="date" name="date" value="{{ $date }}"
class="w-full px-4 py-2.5 border border-gray-200 rounded-xl text-sm bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition shadow-sm">
<p class="mt-2 text-[11px] font-semibold text-emerald-600" x-show="terisiCount > 0">
<i class="fa-solid fa-circle-check"></i> <span x-text="terisiCount"></span> kelas terisi pada <span class="underline decoration-dotted" x-text="date"></span>
</p>
<p class="mt-2 text-[11px] font-semibold text-amber-600" x-show="terisiCount === 0">
<i class="fa-solid fa-circle-info"></i> Belum ada kelas terisi pada <span class="underline decoration-dotted" x-text="date"></span> — coba pilih tanggal lain
</p>
</div>
<div class="flex items-center pt-[22px]">
<button type="submit"
@@ -308,5 +308,32 @@ function rotateStatus(studentId, lessonHour) {
btn.textContent = STATUS_LABELS[next];
btn.title = STATUS_FULL[next];
}
function attendanceLink() {
return {
date: '{{ $date }}',
sel: '{{ $className }}',
status: @json($classAttendanceStatus),
get classList() {
return Object.keys(this.status || {});
},
get terisiCount() {
return Object.values(this.status || {}).filter(s => s.has_data).length;
},
label(cn) {
const s = this.status[cn];
if (!s) return cn;
return s.has_data ? '✅ ' + cn + ' (' + s.recorded + '/' + s.total + ')' : '⬜ ' + cn;
},
async refreshStatus(ev) {
if (ev && ev.target && ev.target.value) this.date = ev.target.value;
try {
const res = await fetch('{{ route("attendances.availability") }}?date=' + encodeURIComponent(this.date));
const j = await res.json();
this.status = j;
} catch (e) {}
},
};
}
</script>
@endpush