Sederhanakan ambang SP: hapus kolom max_points

- max_points tidak pernah dipakai logika penerbitan SP (trigger hanya baca
  min_points: level dgn ambang tertinggi <= total poin siswa)
- Migrasi drop kolom; model, MasterDataController, ResetController (seeder)
  dibersihkan; form Ambang SP & form tambah cukup satu angka (Min Poin)
- Dashboard Ambang SP: batas atas level dihitung dari min_points level
  berikutnya (level terakhir = tak terbatas), urutan dijamin orderBy min_points
- Test: 29 passed / 99 assertion
This commit is contained in:
Novy San87
2026-08-03 14:22:44 +07:00
parent e815bd28d5
commit 279ef07ae2
8 changed files with 47 additions and 35 deletions
+9 -5
View File
@@ -218,12 +218,16 @@
</div>
</div>
<div class="p-5 space-y-3">
@foreach($spThresholds as $threshold)
@foreach($spThresholds as $i => $threshold)
@php
$studentsAtRisk = \App\Models\Student::where('is_active', true)->get()->filter(function($s) use ($threshold) {
// Batas atas level ini = ambang minimal level berikutnya
$nextMin = $spThresholds[$i + 1]->min_points ?? null;
$studentsAtRisk = \App\Models\Student::where('is_active', true)->get()->filter(function($s) use ($threshold, $nextMin) {
$pts = $s->total_points;
$maxOk = $threshold->max_points ?? 9999;
return $pts >= $threshold->min_points && $pts <= $maxOk;
if ($nextMin !== null) {
return $pts >= $threshold->min_points && $pts < $nextMin;
}
return $pts >= $threshold->min_points;
});
$count = $studentsAtRisk->count();
@endphp
@@ -232,7 +236,7 @@
<div class="flex items-center justify-between relative z-10">
<div>
<p class="text-sm font-bold" style="color: {{ $threshold->color }}">{{ $threshold->name }}</p>
<p class="text-xs text-gray-400 mt-0.5">{{ $threshold->min_points }}{{ $threshold->max_points ? '–'.$threshold->max_points : '+' }} poin</p>
<p class="text-xs text-gray-400 mt-0.5">{{ $threshold->min_points }}{{ $nextMin !== null ? '–'.($nextMin - 1) : '+' }} poin</p>
</div>
<div class="text-center">
<p class="text-2xl font-bold" style="color: {{ $threshold->color }}">{{ $count }}</p>
+6 -20
View File
@@ -53,9 +53,7 @@
style="{{ $t->is_active ? 'background-color: ' . $t->color : '' }}"></div>
</label>
</div>
<p class="text-xs text-gray-400 mt-0.5">Min {{ $t->min_points }} poin
@if($t->max_points) – Maks {{ $t->max_points }} poin @else + (tak terbatas) @endif
</p>
<p class="text-xs text-gray-400 mt-0.5">Mulai dari {{ $t->min_points }} poin</p>
</div>
</div>
<div class="flex items-center gap-1 flex-shrink-0">
@@ -73,7 +71,7 @@
</div>
{{-- Fields --}}
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3">
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
<div>
<label class="block text-[11px] font-semibold text-gray-400 uppercase tracking-wider mb-1">Nama</label>
<input type="text" name="thresholds[{{ $loop->index }}][name]" value="{{ $t->name }}"
@@ -84,11 +82,6 @@
<input type="number" name="thresholds[{{ $loop->index }}][min_points]" value="{{ $t->min_points }}" min="0"
class="w-full px-3.5 py-2 border border-gray-200 rounded-xl text-sm bg-gray-50/50 focus:bg-white focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition">
</div>
<div>
<label class="block text-[11px] font-semibold text-gray-400 uppercase tracking-wider mb-1">Maks Poin</label>
<input type="number" name="thresholds[{{ $loop->index }}][max_points]" value="{{ $t->max_points }}" min="0" placeholder="Tak terbatas"
class="w-full px-3.5 py-2 border border-gray-200 rounded-xl text-sm bg-gray-50/50 focus:bg-white focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition">
</div>
<div>
<label class="block text-[11px] font-semibold text-gray-400 uppercase tracking-wider mb-1">Deskripsi</label>
<input type="text" name="thresholds[{{ $loop->index }}][default_description]" value="{{ $t->default_description }}"
@@ -159,17 +152,10 @@
<input type="text" name="name" placeholder="SP 4, SP 5, dll" required
class="w-full px-4 py-2.5 border border-gray-200 rounded-xl text-sm bg-gray-50/50 focus:bg-white focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition">
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Minimal Poin <span class="text-red-500">*</span></label>
<input type="number" name="min_points" min="0" value="200" required
class="w-full px-4 py-2.5 border border-gray-200 rounded-xl text-sm bg-gray-50/50 focus:bg-white focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Maksimal Poin</label>
<input type="number" name="max_points" min="0" placeholder="Tak terbatas"
class="w-full px-4 py-2.5 border border-gray-200 rounded-xl text-sm bg-gray-50/50 focus:bg-white focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Minimal Poin <span class="text-red-500">*</span></label>
<input type="number" name="min_points" min="0" value="200" required
class="w-full px-4 py-2.5 border border-gray-200 rounded-xl text-sm bg-gray-50/50 focus:bg-white focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-1">Deskripsi</label>