@extends('admin.layouts.app') @section('title', 'Assessment Bank') @section('page-title', 'Final Assessment') @section('page-title-jp', '最終試験管理') @section('content') @php // $component is a reserved Blade variable inside component slots → alias it immediately $selectedComponent = $component; $componentLabels = [ 'vocab' => 'Kosakata', 'kanji' => 'Kanji', 'grammar' => 'Tata Bahasa', 'reading' => 'Membaca', 'listening' => 'Menyimak', ]; $componentIcons = [ 'vocab' => '', 'kanji' => '', 'grammar' => '', 'reading' => '', 'listening' => '', ]; $metricColors = ['vocab' => 'primary', 'kanji' => 'warning', 'grammar' => 'success', 'reading' => 'info', 'listening' => 'purple']; $totalItems = $bankCounts->sum('total'); $totalReviewed = $bankCounts->sum('reviewed'); $activeCount = $batches->where('status', 'active')->count(); $pendingReview = $totalItems - $totalReviewed; // Source data readiness helpers $readingNeed = \App\Services\AssessmentService::COMPONENTS['reading']; $listeningNeed = \App\Services\AssessmentService::COMPONENTS['listening']; $readingOk = $readingQuestionCount >= $readingNeed; $listeningOk = $listeningQuestionCount >= $listeningNeed; @endphp {{-- ── Workflow steps ─────────────────────────────────────────────────────── --}}
1
Generate Soal
Buat soal dari data domain (kosakata, kanji, grammar, reading, listening)
2
Review & Edit
Periksa, edit, atau generate ulang; tandai soal yang layak pakai
3
Rakit Batch
Susun soal yang sudah direview ke dalam satu paket ujian (draft)
4
Aktifkan Batch
Batch aktif → user dapat mengerjakan ujian level ini
{{-- ── Level tabs ──────────────────────────────────────────────────────────── --}} {{-- ── Generate Full Exam ──────────────────────────────────────────────────── --}} @php $examTotal = array_sum($examCounts); @endphp
🎯
Generate Full Final Assessment — {{ $level }}
Buat ujian lengkap standar JLPT dalam satu klik: {{ $examCounts['kanji'] ?? 0 }} kanji, {{ $examCounts['vocab'] ?? 0 }} kosakata, {{ $examCounts['grammar'] ?? 0 }} tata bahasa, {{ $examCounts['reading'] ?? 0 }} membaca, {{ $examCounts['listening'] ?? 0 }} menyimak = {{ $examTotal }} soal
Kesiapan Data Sumber:
@foreach ($sourceReadiness as $comp => $info)
{{ $info['ready'] ? '✓' : '⚠' }} {{ $componentLabels[$comp] ?? ucfirst($comp) }} ({{ $level }}): {{ $info['available'] }} tersedia / {{ $info['need'] }} dibutuhkan @if (!$info['ready'] && $comp === 'reading') (akan di-generate otomatis) @elseif (!$info['ready'] && $comp === 'listening') (akan diproses dari audio pool) @endif
@endforeach
@csrf
Kode unik yang dimasukkan user untuk mengakses ujian ini. Kosongkan untuk auto-generate.
{{-- ── Source Data Preparation ──────────────────────────────────────────────── --}}
{{-- Reading --}}
📖
Sumber Membaca
@if ($readingPassageCount > 0) {{ $readingPassageCount }} teks · {{ $readingQuestionCount }} pertanyaan @else Belum ada teks untuk {{ $level }} @endif
@if ($readingOk) ✓ Siap @elseif ($readingPassageCount > 0) Kurang @else Kosong @endif

AI generate teks bacaan JLPT + soal pilihan ganda dalam Bahasa Indonesia. Butuh minimal {{ $readingNeed }} soal untuk komponen Membaca.

@csrf
{{-- Listening --}}
🎧
Sumber Menyimak
@if ($audioPoolCount > 0) {{ $audioPoolCount }} file audio · {{ $listeningQuestionCount }} soal tersedia @if ($audioUnprocessedCount > 0) · {{ $audioUnprocessedCount }} belum diproses @endif @elseif ($listeningQuestionCount > 0) {{ $listeningQuestionCount }} soal (pool tidak aktif) @else Belum ada soal untuk {{ $level }} @endif
@if ($listeningOk) ✓ Siap @elseif ($listeningQuestionCount > 0) Kurang @else Kosong @endif
@if ($audioPoolCount > 0)

Whisper mentranskrip setiap file audio baru, lalu GPT membuat soal JLPT dari transkrip. Butuh minimal {{ $listeningNeed }} soal untuk komponen Menyimak. @if ($audioUnprocessedCount === 0) Semua file sudah diproses. @endif

@csrf
@else

Pool audio belum dikonfigurasi untuk level {{ $level }}. Upload file .mp3 ke server, lalu daftarkan pathnya:

config/listening.php
'{{ $level }}' => 'audio/{{ strtolower($level) }}',

Simpan file ke public/audio/{{ strtolower($level) }}/, refresh halaman, lalu tombol generate akan muncul.

@endif
{{-- ── Quick Setup ─────────────────────────────────────────────────────────── --}} @if($activeCount === 0)
Quick Setup Otomatis
Tidak ada batch aktif untuk level {{ $level }}. Tombol ini akan generate soal semua komponen ({{ implode(', ', array_map(fn($c,$n) => "$n $c", array_keys(\App\Services\AssessmentService::COMPONENTS), array_values(\App\Services\AssessmentService::COMPONENTS))) }}), auto-reviewed, langsung rakit batch, dan aktifkan — semua dalam satu klik.
⚠ Soal dibuat otomatis dari data domain tanpa review manual. Disarankan meninjau kualitas soal setelah setup.
@csrf
@else
Level {{ $level }} sudah siap
Terdapat {{ $activeCount }} batch aktif untuk level ini. User sudah dapat mengerjakan ujian. Gunakan Generate/Rakit di bawah jika ingin menambah batch baru.
@csrf
@endif {{-- ── Summary metric cards ─────────────────────────────────────────────────── --}}
@foreach ($components as $c) @php($row = $bankCounts->get($c)) @php($rev = (int)($row->reviewed ?? 0)) @php($tot = (int)($row->total ?? 0)) @php($pct = $tot > 0 ? (int)round($rev / $tot * 100) : 0)
{!! $componentIcons[$c] !!}
{{ $componentLabels[$c] }}
{{ $rev }}/{{ $tot }}
@if($tot === 0) Belum ada soal @elseif($rev === $tot) ✓ Semua sudah direview @else {{ $tot - $rev }} belum direview @endif
@if($tot > 0)
@endif
@endforeach
{{-- ── Generate + Build Batch (side by side) ───────────────────────────────── --}}
{{-- Generate soal --}}
Generate Soal Baru
Langkah 1

Buat soal dari data {{ $level }} yang ada di database. Soal baru berstatus draft sampai direview.

@csrf
{{-- Rakit batch --}}
Rakit Batch Baru
Langkah 3

Tentukan jumlah soal tiap komponen. Hanya soal reviewed yang bisa masuk batch. Isi 0 untuk skip komponen tersebut.

@csrf
@foreach ($components as $c) @php($row = $bankCounts->get($c)) @php($avail = (int)($row->reviewed ?? 0))
@endforeach
{{-- ── Batches ─────────────────────────────────────────────────────────────── --}}
Batch Ujian — {{ $level }}
{{ $activeCount }} batch aktif
@forelse ($batches as $b) #{{ $b->id }} @if($b->exam_code)
{{ $b->exam_code }}
@endif @if($b->status === 'active') ● Aktif @elseif($b->status === 'archived') Arsip @else Draft @endif
@foreach (($b->section_counts ?? []) as $k => $v) @if($v > 0) {{ $componentLabels[$k] ?? $k }}: {{ $v }} @endif @endforeach
{{ $b->batch_items_count }} {{ $b->created_at?->format('d M Y') }} @if($b->activated_at)
Aktif {{ $b->activated_at->format('d M Y') }}
@endif
Preview @if ($b->status === 'draft')
@csrf
@csrf
@endif @if ($b->status !== 'archived')
@csrf
@endif
@csrf @method('DELETE')
@empty Belum ada batch untuk {{ $level }}. Generate & review soal dulu, lalu rakit batch di atas. @endforelse
{{-- ── Reset User Fails ────────────────────────────────────────────────────── --}}
Reset Percobaan Gagal User

User yang gagal 3 kali pada satu kode ujian akan dikunci secara permanen. Gunakan form ini untuk mereset hitungan gagal agar user bisa mencoba lagi.

@csrf
{{-- ── Item bank ───────────────────────────────────────────────────────────── --}}
Bank Soal Aktif — {{ $level }} @if($selectedComponent) {{ $componentLabels[$selectedComponent] }} @endif
Filter: Semua @foreach ($components as $c) {{ $componentLabels[$c] }} @endforeach
@forelse ($items as $item) {{-- Component --}} {{ $componentLabels[$item->component] ?? $item->component }}
v{{ $item->version }}
{{-- Question content --}} @if ($item->isInstruction())
Instruksi Audio
@if (data_get($item->context, 'transcript'))
"{{ Str::limit(data_get($item->context, 'transcript'), 120) }}"
@endif @else
{{ $item->prompt }}
@if ($item->question_label)
{{ $item->question_label }}
@endif
@foreach (($item->choices ?? []) as $c) {{ $c }}{{ $c === $item->answer ? ' ✓' : '' }} @endforeach
{{-- Inline edit panel (hidden by default) --}} @endif {{-- Status --}} @if ($item->isReviewed()) ✓ Reviewed @else Draft @endif @if ($item->times_served > 0) @php($rate = (int) round($item->correctRate() * 100))
{{ $rate }}% benar
{{ $item->correct_count }}/{{ $item->times_served }} kali
@if ($item->times_served >= 5 && $rate <= 20)
⚠ Terlalu susah
@endif
@endif {{-- Actions --}}
@unless ($item->isInstruction()) @endunless @unless ($item->isReviewed())
@csrf
@endunless
@csrf
@csrf
@empty
📝
Belum ada soal aktif{{ $selectedComponent ? " untuk komponen \"" . ($componentLabels[$selectedComponent] ?? $selectedComponent) . "\"" : '' }} di level {{ $level }}.
Gunakan form Generate Soal di atas untuk membuat soal baru.
@endforelse
@endsection