Files
lms-v2/resources/views/pages/admin/exams/question-bank.blade.php
T

217 lines
14 KiB
PHP
Raw Normal View History

2026-05-30 22:15:16 +07:00
@extends('layouts.app')
@section('content')
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<style>
.select2-container .select2-selection--single { height: 38px; border-radius: 0.5rem; border-color: #e2e8f0; background-color: #f8fafc; }
.select2-container--default .select2-selection--single .select2-selection__rendered { line-height: 38px; font-size: 0.875rem; color: #334155; }
.select2-container--default .select2-selection--single .select2-selection__arrow { height: 36px; }
</style>
<div class="max-w-7xl mx-auto px-4 py-8"
x-data="{
selectedQuestions: [],
selectAll: false,
toggleAll() {
if (this.selectAll) {
this.selectedQuestions = Array.from(document.querySelectorAll('.question-checkbox')).map(cb => cb.value);
} else {
this.selectedQuestions = [];
}
},
confirmBulkDelete() {
if(this.selectedQuestions.length === 0) {
alert('Pilih minimal satu soal untuk dihapus!');
return false;
}
return confirm('Yakin ingin menghapus ' + this.selectedQuestions.length + ' soal terpilih secara permanen?');
}
}">
<div class="flex flex-col md:flex-row md:items-center justify-between mb-6 gap-4">
<div>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Bank Soal (Question Bank)</h2>
<p class="text-sm text-slate-500 mt-1">Kelola dan filter total <span class="font-bold text-blue-600">{{ $totalQuestions }}</span> soal ujian/kuis.</p>
</div>
<div class="flex flex-wrap items-center gap-3">
<form action="{{ url('admin/exams/questions/bulk-delete') }}" method="POST" x-show="selectedQuestions.length > 0" x-transition @submit="return confirmBulkDelete()">
@csrf @method('DELETE')
<template x-for="id in selectedQuestions" :key="id">
<input type="hidden" name="question_ids[]" :value="id">
</template>
<button type="submit" class="inline-flex items-center px-4 py-2 bg-red-50 text-red-600 border border-red-200 rounded-lg text-sm font-bold hover:bg-red-100 shadow-sm transition-all">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path></svg>
Bulk Delete (<span x-text="selectedQuestions.length"></span>)
</button>
</form>
<a href="{{ url('admin/exams/questions/import') }}" class="inline-flex items-center px-4 py-2 bg-slate-800 text-white rounded-lg text-sm font-semibold hover:bg-slate-900 shadow-sm transition-all">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"></path></svg>
Import Soal
</a>
<a href="{{ url('admin/exams/questions/create') }}" class="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-semibold hover:bg-blue-700 shadow-sm transition-all">
+ Tambah Soal
</a>
</div>
</div>
<div class="bg-white p-5 rounded-2xl border border-slate-200 shadow-sm mb-6">
<form action="{{ route('admin.exams.questions') }}" method="GET">
<div class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-6 gap-4 mb-4">
<div>
<label class="block text-xs font-semibold text-slate-500 mb-1">Departemen</label>
<select name="department_id" class="select2 w-full text-sm">
<option value="">Semua</option>
@foreach($departments as $dept)
<option value="{{ $dept->id }}" {{ request('department_id') == $dept->id ? 'selected' : '' }}>{{ $dept->name }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-xs font-semibold text-slate-500 mb-1">Posisi</label>
<select name="position_id" class="select2 w-full text-sm">
<option value="">Semua</option>
@foreach($positions as $pos)
<option value="{{ $pos->id }}" {{ request('position_id') == $pos->id ? 'selected' : '' }}>{{ $pos->name }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-xs font-semibold text-slate-500 mb-1">Materi / Modul</label>
</div>
<div>
<label class="block text-xs font-semibold text-slate-500 mb-1">Tipe Soal</label>
<select name="question_type" class="select2 w-full text-sm">
<option value="">Semua</option>
<option value="single" {{ request('question_type') == 'single' ? 'selected' : '' }}>Single Choice</option>
<option value="multiple" {{ request('question_type') == 'multiple' ? 'selected' : '' }}>Multiple Choice</option>
<option value="true_false" {{ request('question_type') == 'true_false' ? 'selected' : '' }}>True / False</option>
<option value="descriptive" {{ request('question_type') == 'descriptive' ? 'selected' : '' }}>Deskriptif</option>
</select>
</div>
<div>
<label class="block text-xs font-semibold text-slate-500 mb-1">Level</label>
<select name="question_level" class="select2 w-full text-sm">
<option value="">Semua</option>
<option value="mudah" {{ request('question_level') == 'mudah' ? 'selected' : '' }}>Mudah (Easy)</option>
<option value="sedang" {{ request('question_level') == 'sedang' ? 'selected' : '' }}>Sedang (Medium)</option>
<option value="sulit" {{ request('question_level') == 'sulit' ? 'selected' : '' }}>Sulit (Hard)</option>
</select>
</div>
<div>
<label class="block text-xs font-semibold text-slate-500 mb-1">Pembuat Soal</label>
<select name="created_by" class="select2 w-full text-sm">
<option value="">Semua</option>
@foreach($creators as $creator)
<option value="{{ $creator->id }}" {{ request('created_by') == $creator->id ? 'selected' : '' }}>{{ $creator->first_name }}</option>
@endforeach
</select>
</div>
</div>
<div class="flex flex-col md:flex-row gap-4 items-center justify-between border-t border-slate-100 pt-4">
<div class="w-full md:w-1/3">
<input type="text" name="search" value="{{ request('search') }}" placeholder="Cari teks pertanyaan..." class="w-full px-4 py-2 bg-slate-50 border border-slate-200 rounded-lg text-sm focus:ring-blue-500">
</div>
<div class="flex gap-2 w-full md:w-auto">
@if(request()->hasAny(['search', 'department_id', 'position_id', 'question_type', 'question_level', 'created_by']))
<a href="{{ route('admin.exams.questions') }}" class="px-5 py-2 bg-slate-100 text-slate-600 rounded-lg text-sm font-semibold hover:bg-slate-200 transition-all text-center w-full md:w-auto">Reset</a>
@endif
<button type="submit" class="px-5 py-2 bg-blue-600 text-white rounded-lg text-sm font-semibold hover:bg-blue-700 transition-all text-center w-full md:w-auto">
Terapkan Filter
</button>
</div>
</div>
</form>
</div>
<div class="bg-white border border-slate-200 rounded-2xl overflow-hidden shadow-sm">
<div class="overflow-x-auto">
<table class="w-full text-left text-sm">
<thead class="bg-slate-50 text-slate-600 text-xs uppercase tracking-wider border-b border-slate-200">
<tr>
<th class="px-4 py-4 w-10 text-center">
<input type="checkbox" x-model="selectAll" @change="toggleAll" class="w-4 h-4 text-blue-600 border-slate-300 rounded focus:ring-blue-500 cursor-pointer">
</th>
<th class="px-4 py-4 font-semibold">Q.ID</th>
<th class="px-4 py-4 font-semibold">Materi / Modul</th>
<th class="px-4 py-4 font-semibold">Tipe & Level</th>
<th class="px-4 py-4 font-semibold w-1/3">Pertanyaan</th>
<th class="px-4 py-4 font-semibold">Pembuat</th>
<th class="px-4 py-4 font-semibold text-right">Aksi</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700">
@forelse($questions as $q)
<tr class="hover:bg-slate-50 transition-colors" :class="selectedQuestions.includes('{{ $q->id }}') ? 'bg-blue-50/50' : ''">
<td class="px-4 py-3 text-center">
<input type="checkbox" value="{{ $q->id }}" x-model="selectedQuestions" class="question-checkbox w-4 h-4 text-blue-600 border-slate-300 rounded focus:ring-blue-500 cursor-pointer">
</td>
<td class="px-4 py-3 font-mono font-bold text-slate-500">{{ $q->id }}</td>
<td class="px-4 py-3">
<span class="font-semibold text-slate-800">{{ $q->matrix->title ?? 'Umum' }}</span>
<div class="text-[11px] text-slate-500 mt-0.5">{{ $q->department->name ?? 'All Dept' }}</div>
</td>
<td class="px-4 py-3">
<span class="px-2 py-0.5 bg-indigo-50 text-indigo-700 rounded text-[10px] font-bold uppercase tracking-wider border border-indigo-100">{{ str_replace('_', ' ', $q->type) }}</span>
<div class="mt-1">
@if($q->level == 'mudah') <span class="text-[11px] font-bold text-emerald-500">Mudah</span>
@elseif($q->level == 'sedang') <span class="text-[11px] font-bold text-amber-500">Sedang</span>
@else <span class="text-[11px] font-bold text-red-500">Sulit</span> @endif
</div>
</td>
<td class="px-4 py-3">
<p class="text-sm text-slate-800 line-clamp-2">{{ strip_tags($q->question_text) }}</p>
</td>
<td class="px-4 py-3">
<div class="text-sm font-semibold">{{ $q->creator->first_name ?? 'Sistem' }}</div>
<div class="text-[11px] text-slate-400">@if($q->creator && $q->creator->hasRole('trainer')) Trainer @else Admin @endif</div>
</td>
<td class="px-4 py-3 text-right space-x-2 whitespace-nowrap">
<a href="#" class="text-slate-400 hover:text-blue-600"><svg class="w-5 h-5 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path></svg></a>
<a href="#" class="text-slate-400 hover:text-amber-500"><svg class="w-5 h-5 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path></svg></a>
<form action="#" method="POST" class="inline-block" onsubmit="return confirm('Hapus soal ini?');">
@csrf @method('DELETE')
<button type="submit" class="text-slate-400 hover:text-red-500"><svg class="w-5 h-5 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path></svg></button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="7" class="px-4 py-12 text-center">
<svg class="w-12 h-12 text-slate-300 mx-auto mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path></svg>
<p class="text-slate-500 font-medium">Belum ada data soal yang sesuai filter.</p>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@if($questions->hasPages())
<div class="p-4 border-t border-slate-100 bg-slate-50/50">
{{ $questions->links() }}
</div>
@endif
</div>
</div>
<script>
$(document).ready(function() {
// Inisialisasi Select2 untuk semua filter
$('.select2').select2({ width: '100%' });
});
</script>
@endsection