Initial commit - lms-v2 + CLAUDE.md

This commit is contained in:
Iwit
2026-05-30 22:15:16 +07:00
commit 5811409e2d
183 changed files with 23225 additions and 0 deletions
@@ -0,0 +1,47 @@
@extends('layouts.app')
@section('title', 'Dashboard HR - LMS V2.0')
@section('content')
<div class="max-w-7xl mx-auto">
<div class="mb-8 flex justify-between items-end">
<div>
<h1 class="text-3xl font-extrabold text-slate-900 tracking-tight">Statistik Pelatihan CPOB</h1>
<p class="text-sm text-slate-500 mt-1">Ringkasan performa dan kepatuhan training karyawan bulan ini.</p>
</div>
<div>
<button class="bg-indigo-600 text-white px-4 py-2 rounded-md shadow hover:bg-indigo-700 text-sm font-semibold">
+ Buat Ujian Baru
</button>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
<div class="bg-white p-6 rounded-xl shadow-sm border border-slate-100">
<p class="text-xs font-bold text-slate-400 uppercase">Total Karyawan</p>
<h3 class="text-3xl font-bold text-slate-900 mt-1">{{ $statistics['total_karyawan'] }}</h3>
</div>
<div class="bg-white p-6 rounded-xl shadow-sm border border-slate-100">
<p class="text-xs font-bold text-slate-400 uppercase">Trainer Internal</p>
<h3 class="text-3xl font-bold text-slate-900 mt-1">{{ $statistics['total_trainer'] }}</h3>
</div>
<div class="bg-white p-6 rounded-xl shadow-sm border border-slate-100">
<p class="text-xs font-bold text-slate-400 uppercase">SOP Aktif</p>
<h3 class="text-3xl font-bold text-slate-900 mt-1">{{ $statistics['total_sop'] }}</h3>
</div>
<div class="bg-white p-6 rounded-xl shadow-sm border border-slate-100">
<p class="text-xs font-bold text-slate-400 uppercase">Total Kelulusan</p>
<h3 class="text-3xl font-bold text-emerald-600 mt-1">{{ $statistics['lulus_ujian'] }}</h3>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-slate-100 p-6">
<h3 class="text-lg font-bold text-slate-900 mb-4">Matriks Kepatuhan SOP Departemen</h3>
@livewire('matrix.compliance-monitor')
</div>
</div>
@endsection
@@ -0,0 +1,36 @@
@extends('layouts.app')
@section('content')
<div class="max-w-3xl mx-auto px-4 py-8">
<div class="mb-6 flex items-center space-x-3">
<a href="{{ route('admin.departments.index') }}" class="text-slate-400 hover:text-indigo-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Tambah Departemen Baru</h2>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
<form action="{{ route('admin.departments.store') }}" method="POST" class="p-6 sm:p-8 space-y-6">
@csrf
<div>
<label for="name" class="block text-sm font-bold text-slate-700 mb-2">Nama Departemen <span class="text-red-500">*</span></label>
<input type="text" name="name" id="name" value="{{ old('name') }}" required placeholder="Contoh: Quality Assurance"
class="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-600 transition-all">
@error('name') <span class="text-xs text-red-500 mt-1 block">{{ $message }}</span> @enderror
</div>
<div>
<label for="code" class="block text-sm font-bold text-slate-700 mb-2">Kode Departemen</label>
<input type="text" name="code" id="code" value="{{ old('code') }}" placeholder="Contoh: QA"
class="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-600 transition-all uppercase">
</div>
<div class="pt-4 flex justify-end space-x-3 border-t border-slate-100">
<a href="{{ route('admin.departments.index') }}" class="px-5 py-2.5 text-sm font-semibold text-slate-600 hover:bg-slate-100 rounded-xl transition-colors">Batal</a>
<button type="submit" class="px-5 py-2.5 text-sm font-semibold text-white bg-indigo-600 hover:bg-indigo-700 rounded-xl shadow-md transition-all">Simpan Departemen</button>
</div>
</form>
</div>
</div>
@endsection
@@ -0,0 +1,37 @@
@extends('layouts.app')
@section('content')
<div class="max-w-3xl mx-auto px-4 py-8">
<div class="mb-6 flex items-center space-x-3">
<a href="{{ route('admin.departments.index') }}" class="text-slate-400 hover:text-indigo-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Edit Departemen Baru</h2>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
<form action="{{ route('admin.departments.update', $department->id) }}" method="POST" class="p-6 sm:p-8 space-y-6">
@csrf
@method('PUT')
<div>
<label for="name" class="block text-sm font-bold text-slate-700 mb-2">Nama Departemen <span class="text-red-500">*</span></label>
<input type="text" name="name" id="name" value="{{ old('name', $department->name) }}" required placeholder="Contoh: Quality Assurance"
class="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-600 transition-all">
@error('name') <span class="text-xs text-red-500 mt-1 block">{{ $message }}</span> @enderror
</div>
<div>
<label for="code" class="block text-sm font-bold text-slate-700 mb-2">Kode Departemen</label>
<input type="text" name="code" id="code" value="{{ old('code', $department->code) }}" placeholder="Contoh: QA"
class="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-600 transition-all uppercase">
</div>
<div class="pt-4 flex justify-end space-x-3 border-t border-slate-100">
<a href="{{ route('admin.departments.index') }}" class="px-5 py-2.5 text-sm font-semibold text-slate-600 hover:bg-slate-100 rounded-xl transition-colors">Batal</a>
<button type="submit" class="px-5 py-2.5 text-sm font-semibold text-white bg-indigo-600 hover:bg-indigo-700 rounded-xl shadow-md transition-all">Simpan Departemen</button>
</div>
</form>
</div>
</div>
@endsection
@@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
<title>Laporan Data Departemen</title>
<style>
body { font-family: sans-serif; font-size: 12px; color: #333; }
.header { text-align: center; margin-bottom: 20px; border-bottom: 2px solid #222; padding-bottom: 10px; }
.metadata { text-align: right; font-size: 10px; color: #666; margin-bottom: 20px; }
table { width: 100%; border-collapse: collapse; margin-top: 10px; }
th, td { border: 1px solid #ddd; padding: 8px 10px; text-align: left; }
th { background-color: #f4f4f5; color: #111; text-transform: uppercase; font-size: 11px; }
tr:nth-child(even) { background-color: #fafafa; }
</style>
</head>
<body>
<div class="header">
<h2>PT TUNGGAL IDAMAN ABDI (TUNGGAL PHARMA)</h2>
<h3>Laporan Master Data: Departemen</h3>
</div>
<div class="metadata">
Dicetak pada: <strong>{{ $metadata['download_time'] }}</strong><br>
Diunduh oleh: <strong>{{ $metadata['downloaded_by'] }}</strong><br>
Total Rekor: <strong>{{ $metadata['total_data'] }} Departemen</strong>
</div>
<table>
<thead>
<tr>
<th width="10%">ID</th>
<th width="20%">KODE</th>
<th width="70%">NAMA DEPARTEMEN</th>
</tr>
</thead>
<tbody>
@foreach($departments as $dept)
<tr>
<td>{{ $dept->id }}</td>
<td>{{ $dept->code ?? '-' }}</td>
<td>{{ $dept->name }}</td>
</tr>
@endforeach
</tbody>
</table>
</body>
</html>
@@ -0,0 +1,112 @@
@extends('layouts.app')
@section('content')
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"
x-data="{
showCols: { id: true, code: true, name: true, action: true },
exportOpen: false,
columnOpen: false
}">
<div class="flex flex-col md:flex-row md:items-center justify-between mb-8 gap-4">
<div>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Manajemen Departemen</h2>
<p class="text-sm text-slate-500 mt-1">Total <span class="font-bold text-indigo-600">{{ $departments instanceof \Illuminate\Contracts\Pagination\LengthAwarePaginator ? $departments->total() : $departments->count() }}</span> rekor ditemukan.</p>
</div>
<a href="{{ route('admin.departments.create') }}" class="inline-flex items-center justify-center px-4 py-2 bg-indigo-600 text-white rounded-lg text-sm font-semibold hover:bg-indigo-700 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="M12 4v16m8-8H4"></path></svg>
Tambah Departemen
</a>
</div>
<div class="bg-white p-4 rounded-t-2xl border border-slate-200 border-b-0 flex flex-col md:flex-row gap-4 justify-between items-center relative z-10">
<form action="{{ route('admin.departments.index') }}" method="GET" class="w-full md:w-96 relative">
<input type="text" name="search" value="{{ request('search') }}" placeholder="Cari nama atau kode..."
class="w-full pl-10 pr-4 py-2 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-600 transition-all">
<svg class="w-4 h-4 text-slate-400 absolute left-3.5 top-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
@if(request('search'))
<a href="{{ route('admin.departments.index') }}" class="absolute right-3 top-2.5 text-xs text-red-500 hover:underline">Clear</a>
@endif
</form>
<div class="flex items-center space-x-3 w-full md:w-auto">
<div class="relative">
<button @click="columnOpen = !columnOpen" @click.away="columnOpen = false" class="px-4 py-2 bg-white border border-slate-200 text-slate-700 rounded-xl text-sm font-semibold hover:bg-slate-50 flex items-center shadow-sm">
<svg class="w-4 h-4 mr-2 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2"></path></svg>
Kolom
</button>
<div x-show="columnOpen" x-transition class="absolute right-0 mt-2 w-48 bg-white border border-slate-100 rounded-xl shadow-xl py-2 z-50" style="display: none;">
<label class="flex items-center px-4 py-2 hover:bg-slate-50 cursor-pointer text-sm"><input type="checkbox" x-model="showCols.id" class="rounded border-slate-300 text-indigo-600 mr-3"> ID</label>
<label class="flex items-center px-4 py-2 hover:bg-slate-50 cursor-pointer text-sm"><input type="checkbox" x-model="showCols.code" class="rounded border-slate-300 text-indigo-600 mr-3"> Kode</label>
<label class="flex items-center px-4 py-2 hover:bg-slate-50 cursor-pointer text-sm"><input type="checkbox" x-model="showCols.name" class="rounded border-slate-300 text-indigo-600 mr-3"> Nama Departemen</label>
</div>
</div>
<div class="relative">
<button @click="exportOpen = !exportOpen" @click.away="exportOpen = false" class="px-4 py-2 bg-emerald-50 border border-emerald-200 text-emerald-700 rounded-xl text-sm font-semibold hover:bg-emerald-100 flex items-center 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-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
Export Data
</button>
<div x-show="exportOpen" x-transition class="absolute right-0 mt-2 w-48 bg-white border border-slate-100 rounded-xl shadow-xl py-2 z-50" style="display: none;">
<p class="px-4 py-1 text-[10px] font-bold text-slate-400 uppercase tracking-wider">Pilih Format</p>
<a href="{{ url('admin/departments/export/excel?search=' . request('search')) }}" class="flex items-center px-4 py-2 hover:bg-slate-50 text-sm text-slate-700">
<span class="w-2 h-2 rounded-full bg-emerald-500 mr-2"></span> Excel (.xlsx)
</a>
<a href="{{ url('admin/departments/export/pdf?search=' . request('search')) }}" class="flex items-center px-4 py-2 hover:bg-slate-50 text-sm text-slate-700">
<span class="w-2 h-2 rounded-full bg-red-500 mr-2"></span> PDF (.pdf)
</a>
</div>
</div>
</div>
</div>
<div class="bg-white border border-slate-200 rounded-b-2xl overflow-hidden shadow-sm relative z-0">
<div class="overflow-x-auto">
<table class="w-full text-left text-sm whitespace-nowrap">
<thead class="bg-slate-50/80 text-slate-500 text-xs uppercase tracking-wider border-b border-slate-200">
<tr>
<th x-show="showCols.id" class="px-6 py-4 font-semibold">ID</th>
<th x-show="showCols.code" class="px-6 py-4 font-semibold">Kode</th>
<th x-show="showCols.name" class="px-6 py-4 font-semibold">Nama Departemen</th>
<th x-show="showCols.action" class="px-6 py-4 font-semibold text-right">Aksi</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700">
@forelse($departments as $dept)
<tr class="hover:bg-slate-50 transition-colors">
<td x-show="showCols.id" class="px-6 py-4 font-medium text-slate-500">#{{ $dept->id }}</td>
<td x-show="showCols.code" class="px-6 py-4">
<span class="bg-slate-100 text-slate-600 px-2.5 py-1 rounded-md text-xs font-bold border border-slate-200">{{ $dept->code ?? 'N/A' }}</span>
</td>
<td x-show="showCols.name" class="px-6 py-4 font-bold text-slate-900">{{ $dept->name }}</td>
<td x-show="showCols.action" class="px-6 py-4 text-right space-x-3">
<a href="{{ route('admin.departments.show', $dept->id) }}" class="text-slate-400 hover:text-indigo-600 font-medium text-sm transition-colors">Detail</a>
<a href="{{ route('admin.departments.edit', $dept->id) }}" class="text-indigo-600 hover:text-indigo-800 font-medium text-sm transition-colors">Edit</a>
<form action="{{ route('admin.departments.destroy', $dept->id) }}" method="POST" class="inline-block" onsubmit="return confirm('Apakah Anda yakin ingin menghapus departemen ini?');">
@csrf @method('DELETE')
<button type="submit" class="text-red-500 hover:text-red-700 font-medium text-sm transition-colors">Hapus</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="4" class="px-6 py-12 text-center text-slate-500">
<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="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"></path></svg>
Tidak ada data departemen yang ditemukan.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@if(method_exists($departments, 'hasPages') && $departments->hasPages())
<div class="p-4 border-t border-slate-100 bg-slate-50/50">
{{ $departments->links() }}
</div>
@endif
</div>
</div>
@endsection
@@ -0,0 +1,141 @@
@extends('layouts.app')
@section('content')
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div class="flex items-center justify-between mb-6">
<div>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Detail Departemen</h2>
<p class="text-sm text-slate-500 mt-1">Informasi lengkap mengenai departemen.</p>
</div>
<a href="{{ route('admin.departments.index') }}" class="inline-flex items-center px-4 py-2 bg-slate-100 text-slate-700 rounded-lg text-sm font-semibold hover:bg-slate-200 transition-colors">
<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="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
Kembali
</a>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
<div class="p-6 sm:p-10">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h3 class="text-lg font-semibold text-slate-800 mb-4 pb-2 border-b border-slate-100">Informasi Utama</h3>
<div class="space-y-4">
<div>
<span class="block text-sm font-medium text-slate-500 mb-1">Kode Departemen</span>
<div class="inline-block bg-slate-100 text-slate-700 px-3 py-1 rounded-md text-sm font-bold border border-slate-200">
{{ $department->code ?? '-' }}
</div>
</div>
<div>
<span class="block text-sm font-medium text-slate-500 mb-1">Nama Departemen</span>
<div class="text-lg font-bold text-slate-900">
{{ $department->name }}
</div>
</div>
</div>
</div>
<div>
<h3 class="text-lg font-semibold text-slate-800 mb-4 pb-2 border-b border-slate-100">Informasi Sistem</h3>
<div class="space-y-4">
<div>
<span class="block text-sm font-medium text-slate-500 mb-1">ID Sistem</span>
<div class="text-sm text-slate-900 font-mono bg-slate-50 inline-block px-2 py-1 rounded border border-slate-100">
#{{ $department->id }}
</div>
</div>
<div>
<span class="block text-sm font-medium text-slate-500 mb-1">Tanggal Dibuat</span>
<div class="text-sm text-slate-900">
{{ $department->created_at ? $department->created_at->format('d F Y, H:i') : '-' }}
</div>
</div>
<div>
<span class="block text-sm font-medium text-slate-500 mb-1">Terakhir Diperbarui</span>
<div class="text-sm text-slate-900">
{{ $department->updated_at ? $department->updated_at->diffForHumans() : '-' }}
</div>
</div>
</div>
</div>
</div>
<div class="mt-10 pt-8 border-t border-slate-100">
<h3 class="text-lg font-semibold text-slate-800 mb-6">Pemetaan & Statistik</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="bg-indigo-50 border border-indigo-100 rounded-xl p-6 flex items-center">
<div class="p-3 bg-indigo-100 text-indigo-600 rounded-lg mr-4">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path></svg>
</div>
<div>
<p class="text-sm font-medium text-slate-500">Total Karyawan Aktif</p>
<p class="text-2xl font-bold text-slate-900">{{ $department->users()->count() }} Orang</p>
</div>
</div>
<div class="bg-slate-50 border border-slate-100 rounded-xl p-6">
<p class="text-sm font-medium text-slate-500 mb-3">Posisi / Jabatan pada Departemen ini ({{ $department->positions()->count() }})</p>
<div class="flex flex-wrap gap-2">
@forelse($department->positions as $pos)
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-semibold bg-white border border-slate-200 text-slate-700 shadow-sm">
{{ $pos->name }}
</span>
@empty
<span class="text-sm text-slate-400 italic">Belum ada posisi yang dipetakan.</span>
@endforelse
</div>
</div>
</div>
</div>
<div class="mt-10 pt-8 border-t border-slate-100">
<h3 class="text-lg font-semibold text-slate-800 mb-4">Daftar Karyawan di Departemen Ini</h3>
<div class="bg-white border border-slate-200 rounded-xl overflow-hidden shadow-sm">
<div class="overflow-x-auto custom-scrollbar">
<table class="w-full text-left text-sm whitespace-nowrap">
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wider border-b border-slate-200">
<tr>
<th class="px-6 py-3 font-semibold">NIK</th>
<th class="px-6 py-3 font-semibold">Nama Karyawan</th>
<th class="px-6 py-3 font-semibold">Jabatan</th>
<th class="px-6 py-3 font-semibold text-right">Opsi</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700">
@forelse($department->users as $user)
<tr class="hover:bg-slate-50">
<td class="px-6 py-3 font-mono text-xs font-bold">{{ $user->nik ?? '-' }}</td>
<td class="px-6 py-3">
<div class="font-bold text-slate-900">{{ $user->first_name }} {{ $user->last_name }}</div>
<div class="text-xs text-slate-500">{{ $user->email }}</div>
</td>
<td class="px-6 py-3 text-sm">{{ $user->position->name ?? '-' }}</td>
<td class="px-6 py-3 text-right">
<a href="{{ route('admin.employees.show', $user->id) }}" class="text-indigo-600 hover:text-indigo-800 font-medium text-xs">Detail</a>
</td>
</tr>
@empty
<tr>
<td colspan="4" class="px-6 py-8 text-center text-slate-500 italic">Belum ada karyawan di departemen ini.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
<div class="mt-10 pt-6 border-t border-slate-100 flex items-center justify-end space-x-3">
<a href="{{ route('admin.departments.edit', $department->id) }}" class="inline-flex items-center px-4 py-2 bg-indigo-50 text-indigo-700 rounded-lg text-sm font-semibold hover:bg-indigo-100 transition-colors">
<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="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>
Edit Departemen
</a>
</div>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,238 @@
@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>
/* Penyesuaian UI Select2 agar senada dengan Tailwind dan menyembunyikan elemen asli */
.select2-container .select2-selection--single { height: 42px; border-radius: 0.75rem; border-color: #e2e8f0; background-color: #f8fafc; }
.select2-container--default .select2-selection--single .select2-selection__rendered { line-height: 42px; font-size: 0.875rem; color: #334155; padding-left: 1rem; }
.select2-container--default .select2-selection--single .select2-selection__arrow { height: 40px; right: 10px; }
.select2-hidden-accessible { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip: rect(0,0,0,0) !important; white-space: nowrap !important; border: 0 !important; }
</style>
<div class="max-w-5xl mx-auto px-4 py-8">
<div class="mb-6 flex items-center space-x-3">
<a href="{{ route('admin.employees.index') }}" class="text-slate-400 hover:text-blue-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Tambah Karyawan Baru</h2>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
<div class="bg-blue-50/50 p-4 border-b border-slate-100 flex items-start">
<svg class="w-5 h-5 text-blue-600 mt-0.5 mr-3 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
<p class="text-sm text-blue-800">Lengkapi formulir di bawah ini. Password default: <span class="font-mono font-bold bg-white px-2 py-0.5 rounded border border-blue-200">12345678</span></p>
</div>
<form action="{{ route('admin.employees.store') }}" method="POST" enctype="multipart/form-data" class="p-6 sm:p-8 space-y-6">
@csrf
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">NIK <span class="text-red-500">*</span></label>
<input type="text" name="nik" value="{{ old('nik') }}" required class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
@error('nik') <span class="text-xs text-red-500 mt-1 block">{{ $message }}</span> @enderror
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">No. KTP</label>
<input type="text" name="identity_number" value="{{ old('identity_number') }}" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Inisial <span class="text-blue-500 font-normal text-xs">(Auto Suggest)</span></label>
<input type="text" name="initial" id="initial" value="{{ old('initial') }}" maxlength="3" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm uppercase">
</div>
<div class="lg:col-span-2">
<label class="block text-sm font-bold text-slate-700 mb-2">Nama Depan <span class="text-red-500">*</span></label>
<input type="text" name="first_name" id="first_name" value="{{ old('first_name') }}" required class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
@error('first_name') <span class="text-xs text-red-500 mt-1 block">{{ $message }}</span> @enderror
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Nama Belakang</label>
<input type="text" name="last_name" id="last_name" value="{{ old('last_name') }}" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div class="lg:col-span-2">
<label class="block text-sm font-bold text-slate-700 mb-2">Email Perusahaan <span class="text-red-500">*</span></label>
<input type="email" name="email" value="{{ old('email') }}" required class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
@error('email') <span class="text-xs text-red-500 mt-1 block">{{ $message }}</span> @enderror
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">No. HP / WA</label>
<input type="text" name="phone" value="{{ old('phone') }}" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Jenis Kelamin <span class="text-red-500">*</span></label>
<select name="gender" class="select2 w-full text-sm" required>
<option value="">-- Pilih --</option>
<option value="L" {{ old('gender') == 'L' ? 'selected' : '' }}>Laki-laki</option>
<option value="P" {{ old('gender') == 'P' ? 'selected' : '' }}>Perempuan</option>
</select>
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Tanggal Lahir</label>
<input type="date" name="date_of_birth" value="{{ old('date_of_birth') }}" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Tanggal Bergabung</label>
<input type="date" name="join_date" value="{{ old('join_date') }}" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Departemen <span class="text-red-500">*</span></label>
<select name="department_id" id="deptSelect" class="select2 w-full text-sm" required>
<option value="">-- Pilih Departemen --</option>
@foreach($departments as $dept)
<option value="{{ $dept->id }}" {{ old('department_id') == $dept->id ? 'selected' : '' }}>{{ $dept->name }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Posisi / Jabatan <span class="text-red-500">*</span></label>
<select name="position_id" id="posSelect" class="select2 w-full text-sm" required>
<option value="">-- Pilih Dept Terlebih Dahulu --</option>
</select>
</div>
<div class="bg-slate-50 p-4 border border-slate-200 rounded-xl">
<label class="block text-sm font-bold text-slate-700 mb-2">Hak Akses Sistem Utama <span class="text-red-500">*</span></label>
<select name="role" class="select2 w-full text-sm" required>
<option value="karyawan" {{ old('role') == 'karyawan' ? 'selected' : '' }}>Trainee (Karyawan)</option>
@if(auth()->user()->hasRole('superadmin'))
<option value="admin" {{ old('role') == 'admin' ? 'selected' : '' }}>Administrator</option>
@endif
</select>
<label class="flex items-center space-x-2 cursor-pointer mt-4">
<input type="checkbox" name="is_trainer" value="1" {{ old('is_trainer') ? 'checked' : '' }} class="w-4 h-4 text-blue-600 border-slate-300 rounded focus:ring-blue-500">
<span class="text-sm font-semibold text-slate-700">Jadikan Trainer / Pemateri juga</span>
</label>
</div>
</div>
<div class="border-t border-slate-100 pt-6 mt-6">
<label class="block text-sm font-bold text-slate-700 mb-2">Modul SOP Training (Marketing)</label>
<select name="training_matrix_id" class="select2 w-full text-sm">
<option value="">-- Kosongkan jika bukan Plant Dept --</option>
@foreach($trainingMatrices as $matrix)
<option value="{{ $matrix->id }}" {{ old('training_matrix_id') == $matrix->id ? 'selected' : '' }}>{{ $matrix->title ?? $matrix->name }}</option>
@endforeach
</select>
</div>
<div class="border-t border-slate-100 pt-6 mt-6" x-data="{ documents: [{ id: 1 }], addDocument() { this.documents.push({ id: Date.now() }); }, removeDocument(id) { this.documents = this.documents.filter(doc => doc.id !== id); } }">
<div class="flex justify-between items-center mb-4">
<div>
<label class="block text-sm font-bold text-slate-700">Dokumen Karyawan</label>
<p class="text-xs text-slate-500 mt-1">CV, KTP, Ijazah (Otomatis terunggah ke Nextcloud)</p>
</div>
<button type="button" @click="addDocument()" class="text-xs bg-blue-50 text-blue-700 font-bold px-3 py-1.5 rounded-lg hover:bg-blue-100">
+ Tambah Kolom File
</button>
</div>
<div class="space-y-3">
<template x-for="(doc, index) in documents" :key="doc.id">
<div class="flex items-center gap-3 bg-slate-50 p-3 rounded-lg border border-slate-200">
<span class="text-sm font-bold text-slate-400 w-6" x-text="index + 1 + '.'"></span>
<input type="file" name="documents[]" class="flex-1 text-sm file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100 cursor-pointer">
<button type="button" x-show="documents.length > 1" @click="removeDocument(doc.id)" class="text-red-500 hover:text-red-700 p-2">
Hapus
</button>
</div>
</template>
</div>
</div>
<div class="pt-6 flex justify-end space-x-3 border-t border-slate-100 mt-8">
<a href="{{ route('admin.employees.index') }}" class="px-5 py-2.5 text-sm font-semibold text-slate-600 hover:bg-slate-100 rounded-xl transition-colors">Batal</a>
<button type="submit" class="px-5 py-2.5 text-sm font-semibold text-white bg-blue-600 hover:bg-blue-700 rounded-xl shadow-md transition-all">Simpan Karyawan</button>
</div>
</form>
</div>
</div>
<script>
$(document).ready(function() {
// 1. Inisialisasi Select2 di semua dropdown yang ada class select2
$('.select2').select2({ width: '100%' });
// 2. Logika Dropdown Bertingkat (Dept -> Posisi)
const mapping = @json($deptPosMapping ?? []);
const posSelect = $('#posSelect');
const deptSelect = $('#deptSelect');
const oldPos = "{{ old('position_id') }}";
function updatePositionDropdown() {
let deptId = deptSelect.val();
posSelect.empty();
posSelect.append(new Option('-- Pilih Jabatan --', ''));
if (deptId && mapping[deptId]) {
mapping[deptId].forEach(function(pos) {
let selected = (pos.id == oldPos);
posSelect.append(new Option(pos.name, pos.id, false, selected));
});
} else {
// Munculkan semua jika Dept belum terpilih
@foreach($positions as $p)
posSelect.append(new Option("{{ $p->name }}", "{{ $p->id }}", false, ("{{ $p->id }}" == oldPos)));
@endforeach
}
posSelect.trigger('change.select2');
}
deptSelect.on('change', updatePositionDropdown);
updatePositionDropdown(); // Eksekusi saat load pertama kali
});
// 3. FITUR AUTO-SUGGEST INITIAL 3 DIGIT
document.addEventListener("DOMContentLoaded", function() {
const existingInitials = @json($existingInitials ?? []);
const firstNameInput = document.getElementById('first_name');
const lastNameInput = document.getElementById('last_name');
const initialInput = document.getElementById('initial');
function generateInitial() {
let first = firstNameInput.value.trim().toLowerCase();
let last = lastNameInput.value.trim().toLowerCase();
let fullName = (first + ' ' + last).trim();
if (fullName.length === 0) return;
let words = fullName.split(/\s+/).filter(w => w.length > 0);
let initial = '';
// Algoritma: 3 kata ambil huruf pertama, 2 kata ambil 1 dpn & 2 blkg, 1 kata ambil 3 awal.
if (words.length >= 3) {
initial = words[0][0] + words[1][0] + words[2][0];
} else if (words.length === 2) {
initial = words[0][0] + words[1].substring(0, 2);
} else if (words.length === 1) {
initial = words[0].substring(0, 3);
}
initial = initial.replace(/[^a-z]/g, '');
while(initial.length < 3) { initial += 'x'; }
initial = initial.substring(0, 3);
let baseInitial = initial.substring(0, 2);
let counter = 0;
let alphabet = 'abcdefghijklmnopqrstuvwxyz';
// Cek ke DB: jika inisial sudah ada, ganti huruf ke-3 secara alphabet.
while (existingInitials.includes(initial) && counter < 26) {
initial = baseInitial + alphabet[counter];
counter++;
}
initialInput.value = initial.toUpperCase();
}
firstNameInput.addEventListener('input', generateInitial);
lastNameInput.addEventListener('input', generateInitial);
});
</script>
@endsection
@@ -0,0 +1,171 @@
@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: 42px; border-radius: 0.75rem; border-color: #e2e8f0; background-color: #f8fafc; }
.select2-container--default .select2-selection--single .select2-selection__rendered { line-height: 42px; font-size: 0.875rem; color: #334155; padding-left: 1rem; }
.select2-container--default .select2-selection--single .select2-selection__arrow { height: 40px; right: 10px; }
.select2-hidden-accessible { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip: rect(0,0,0,0) !important; white-space: nowrap !important; border: 0 !important; }
</style>
<div class="max-w-5xl mx-auto px-4 py-8">
<div class="mb-6 flex items-center space-x-3">
<a href="{{ route('admin.employees.index') }}" class="text-slate-400 hover:text-blue-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Edit Data Karyawan</h2>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
<form action="{{ route('admin.employees.update', $employee->id) }}" method="POST" enctype="multipart/form-data" class="p-6 sm:p-8 space-y-6">
@csrf
@method('PUT')
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">NIK <span class="text-red-500">*</span></label>
<input type="text" name="nik" value="{{ old('nik', $employee->nik) }}" required class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">No. KTP</label>
<input type="text" name="identity_number" value="{{ old('identity_number', $employee->identity_number) }}" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Inisial</label>
<input type="text" name="initial" value="{{ old('initial', $employee->initial) }}" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm uppercase">
</div>
<div class="lg:col-span-2">
<label class="block text-sm font-bold text-slate-700 mb-2">Nama Depan <span class="text-red-500">*</span></label>
<input type="text" name="first_name" value="{{ old('first_name', $employee->first_name) }}" required class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Nama Belakang</label>
<input type="text" name="last_name" value="{{ old('last_name', $employee->last_name) }}" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div class="lg:col-span-2">
<label class="block text-sm font-bold text-slate-700 mb-2">Email Perusahaan <span class="text-red-500">*</span></label>
<input type="email" name="email" value="{{ old('email', $employee->email) }}" required class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">No. HP / WA</label>
<input type="text" name="phone" value="{{ old('phone', $employee->phone) }}" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Jenis Kelamin <span class="text-red-500">*</span></label>
<select name="gender" class="select2 w-full text-sm" required>
<option value="L" {{ old('gender', $employee->gender) == 'L' ? 'selected' : '' }}>Laki-laki</option>
<option value="P" {{ old('gender', $employee->gender) == 'P' ? 'selected' : '' }}>Perempuan</option>
</select>
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Tanggal Lahir</label>
<input type="date" name="date_of_birth" value="{{ old('date_of_birth', $employee->date_of_birth ? \Carbon\Carbon::parse($employee->date_of_birth)->format('Y-m-d') : '') }}" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Tanggal Bergabung</label>
<input type="date" name="join_date" value="{{ old('join_date', $employee->join_date ? \Carbon\Carbon::parse($employee->join_date)->format('Y-m-d') : '') }}" class="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Departemen <span class="text-red-500">*</span></label>
<select name="department_id" id="deptSelect" class="select2 w-full text-sm" required>
@foreach($departments as $dept)
<option value="{{ $dept->id }}" {{ old('department_id', $employee->department_id) == $dept->id ? 'selected' : '' }}>{{ $dept->name }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Posisi / Jabatan <span class="text-red-500">*</span></label>
<select name="position_id" id="posSelect" class="select2 w-full text-sm" required>
<option value="">-- Pilih Jabatan --</option>
</select>
</div>
<div class="bg-slate-50 p-4 border border-slate-200 rounded-xl">
<label class="block text-sm font-bold text-slate-700 mb-2">Hak Akses Sistem Utama <span class="text-red-500">*</span></label>
<select name="role" class="select2 w-full text-sm" required>
<option value="karyawan" {{ $employee->hasRole('admin') ? '' : 'selected' }}>Trainee (Karyawan)</option>
@if(auth()->user()->hasRole('superadmin'))
<option value="admin" {{ $employee->hasRole('admin') ? 'selected' : '' }}>Administrator</option>
@endif
</select>
<label class="flex items-center space-x-2 cursor-pointer mt-4">
<input type="checkbox" name="is_trainer" value="1" {{ $employee->hasRole('trainer') ? 'checked' : '' }} class="w-4 h-4 text-blue-600 border-slate-300 rounded focus:ring-blue-500">
<span class="text-sm font-semibold text-slate-700">Tetapkan sebagai Trainer / Pemateri</span>
</label>
</div>
<div class="bg-slate-50 p-4 border border-slate-200 rounded-xl">
<label class="block text-sm font-bold text-slate-700 mb-2">Status Karyawan <span class="text-red-500">*</span></label>
<label class="flex items-center space-x-2 cursor-pointer mt-2">
<input type="checkbox" name="is_active" value="1" {{ old('is_active', $employee->is_active ?? true) ? 'checked' : '' }} class="w-4 h-4 text-emerald-600 border-slate-300 rounded focus:ring-emerald-500">
<span class="text-sm font-semibold text-slate-700">Akun Aktif</span>
</label>
<p class="text-[11px] text-slate-500 mt-2">Hilangkan centang jika karyawan resign.</p>
</div>
</div>
<div class="border-t border-slate-100 pt-6 mt-6">
<label class="block text-sm font-bold text-slate-700 mb-2">Modul SOP Training (Marketing)</label>
<select name="training_matrix_id" class="select2 w-full text-sm">
<option value="">-- Kosongkan jika bukan marketing --</option>
@foreach($trainingMatrices as $matrix)
<option value="{{ $matrix->id }}" {{ old('training_matrix_id', $employee->training_matrix_id) == $matrix->id ? 'selected' : '' }}>{{ $matrix->title ?? $matrix->name }}</option>
@endforeach
</select>
</div>
<div class="border-t border-slate-100 pt-6 mt-6">
<label class="block text-sm font-bold text-slate-700 mb-2">Reset Password (Opsional)</label>
<input type="password" name="password" placeholder="Kosongkan jika tidak ingin mengubah password" class="w-full md:w-1/2 px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm">
</div>
<div class="pt-6 flex justify-end space-x-3 border-t border-slate-100 mt-8">
<a href="{{ route('admin.employees.index') }}" class="px-5 py-2.5 text-sm font-semibold text-slate-600 hover:bg-slate-100 rounded-xl transition-colors">Batal</a>
<button type="submit" class="px-5 py-2.5 text-sm font-semibold text-white bg-blue-600 hover:bg-blue-700 rounded-xl shadow-md transition-all">Perbarui Karyawan</button>
</div>
</form>
</div>
</div>
<script>
$(document).ready(function() {
$('.select2').select2({ width: '100%' });
// Logika Dropdown Bertingkat untuk Edit (Sama dengan Create)
const mapping = @json($deptPosMapping ?? []);
const posSelect = $('#posSelect');
const deptSelect = $('#deptSelect');
const defaultPos = "{{ old('position_id', $employee->position_id) }}";
function updatePositionDropdown() {
let deptId = deptSelect.val();
posSelect.empty();
posSelect.append(new Option('-- Pilih Jabatan --', ''));
if (deptId && mapping[deptId]) {
mapping[deptId].forEach(function(pos) {
let selected = (pos.id == defaultPos);
posSelect.append(new Option(pos.name, pos.id, false, selected));
});
} else {
@foreach($positions as $p)
posSelect.append(new Option("{{ $p->name }}", "{{ $p->id }}", false, ("{{ $p->id }}" == defaultPos)));
@endforeach
}
posSelect.trigger('change.select2');
}
deptSelect.on('change', updatePositionDropdown);
updatePositionDropdown();
});
</script>
@endsection
@@ -0,0 +1,72 @@
@extends('layouts.app')
@section('content')
<div class="max-w-7xl mx-auto px-4 py-8">
<div class="mb-6 flex items-center space-x-3">
<a href="{{ route('admin.employees.import') }}" class="text-slate-400 hover:text-blue-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Pratinjau Data Import</h2>
</div>
<div class="bg-amber-50 border-l-4 border-amber-500 p-4 mb-6 rounded-r-lg">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-amber-400" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" /></svg>
</div>
<div class="ml-3">
<p class="text-sm text-amber-800 font-semibold">Tinjau data Anda!</p>
<p class="text-sm text-amber-700 mt-1">Data di bawah ini belum tersimpan. Pastikan nama kolom dan isi data sudah sesuai. Baris yang NIK, Nama Depan, atau Email-nya kosong akan dilewati (diabaikan).</p>
</div>
</div>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden mb-6">
<div class="overflow-x-auto">
<table class="w-full text-left text-sm whitespace-nowrap">
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wider border-b border-slate-200">
<tr>
<th class="px-6 py-4 font-semibold">NIK</th>
<th class="px-6 py-4 font-semibold">Nama Depan</th>
<th class="px-6 py-4 font-semibold">Nama Belakang</th>
<th class="px-6 py-4 font-semibold">Email</th>
<th class="px-6 py-4 font-semibold">Telepon</th>
<th class="px-6 py-4 font-semibold">ID Dept</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700">
@foreach($rows as $index => $row)
@if($index < 20) <!-- Batasi preview 20 baris saja agar browser tidak berat -->
<tr class="hover:bg-slate-50">
<td class="px-6 py-3 font-mono font-bold">{{ $row['nik'] ?? '-' }}</td>
<td class="px-6 py-3">{{ $row['nama_depan'] ?? '-' }}</td>
<td class="px-6 py-3">{{ $row['nama_belakang'] ?? '-' }}</td>
<td class="px-6 py-3 text-blue-600">{{ $row['email'] ?? '-' }}</td>
<td class="px-6 py-3">{{ $row['telepon'] ?? '-' }}</td>
<td class="px-6 py-3">{{ $row['department_id'] ?? '-' }}</td>
</tr>
@endif
@endforeach
</tbody>
</table>
</div>
@if(count($rows) > 20)
<div class="p-4 text-center text-sm text-slate-500 border-t border-slate-100 bg-slate-50">
... Menampilkan 20 baris pertama dari total <b>{{ count($rows) }}</b> baris data.
</div>
@endif
</div>
<!-- Tombol Aksi -->
<div class="flex items-center justify-end space-x-4">
<a href="{{ route('admin.employees.import') }}" class="px-6 py-2.5 text-sm font-semibold text-slate-600 hover:bg-slate-100 rounded-xl transition-colors">Batal & Kembali</a>
<form action="{{ route('admin.employees.import.process') }}" method="POST">
@csrf
<button type="submit" class="px-6 py-2.5 text-sm font-semibold text-white bg-emerald-600 hover:bg-emerald-700 rounded-xl shadow-md transition-all flex items-center">
<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="M5 13l4 4L19 7"></path></svg>
Konfirmasi & Simpan Permanen
</button>
</form>
</div>
</div>
@endsection
@@ -0,0 +1,42 @@
@extends('layouts.app')
@section('content')
<div class="max-w-4xl mx-auto px-4 py-8">
<div class="mb-6 flex items-center space-x-3">
<a href="{{ route('admin.employees.index') }}" class="text-slate-400 hover:text-blue-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Import Data Karyawan</h2>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Kotak Bantuan Template -->
<div class="bg-blue-50 rounded-2xl p-6 border border-blue-100">
<h3 class="text-lg font-bold text-blue-900 mb-2">1. Unduh Template</h3>
<p class="text-sm text-blue-700 mb-6">Agar proses import berjalan lancar, pastikan Anda menggunakan template Excel/CSV standar dari sistem. Kolom wajib diisi adalah NIK, Nama, dan Email.</p>
<a href="{{ route('admin.employees.import.template') }}" 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">
<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-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
Download Template
</a>
</div>
<!-- Kotak Upload File -->
<div class="bg-white rounded-2xl p-6 border border-slate-200 shadow-sm">
<h3 class="text-lg font-bold text-slate-800 mb-2">2. Unggah File Data</h3>
<p class="text-sm text-blue-700 mb-6 max-w-lg mx-auto">Gunakan format Excel standar dari sistem. Kolom wajib isi: NIK, Nama Depan, Jenis Kelamin dan Email. Tanggal gunakan format YYYY-MM-DD.</p>
<form action="{{ route('admin.employees.import.preview') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="mb-6">
<input type="file" name="file" accept=".xlsx, .xls, .csv" required class="w-full text-sm text-slate-500 file:mr-4 file:py-2.5 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100 cursor-pointer border border-slate-200 rounded-lg p-1 bg-slate-50">
</div>
<button type="submit" class="w-full flex justify-center items-center px-4 py-2.5 text-sm font-semibold text-white bg-slate-800 hover:bg-slate-900 rounded-lg transition-all shadow-md">
Lanjutkan ke Preview
<svg class="w-4 h-4 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path></svg>
</button>
</form>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,288 @@
@extends('layouts.app')
@section('content')
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.2.0"></script>
<style>
/* Kustomisasi Scrollbar */
.custom-scrollbar::-webkit-scrollbar { height: 6px; }
.custom-scrollbar::-webkit-scrollbar-track { background: #f1f5f9; border-radius: 4px; }
.custom-scrollbar::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 4px; }
.custom-scrollbar::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
</style>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"
x-data="{ showCols: { nik: true, name: true, role: true, department: true, action: true }, showCharts: false }">
<div class="flex flex-col md:flex-row md:items-center justify-between mb-8 gap-4">
<div>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Manajemen Karyawan</h2>
<p class="text-sm text-slate-500 mt-1">Total <span class="font-bold text-blue-600">{{ $totalRecords }}</span> data karyawan terdaftar.</p>
</div>
<div class="flex flex-wrap items-center gap-3">
<button @click="showCharts = !showCharts" class="inline-flex items-center px-4 py-2 bg-slate-100 text-slate-700 border border-slate-200 rounded-lg text-sm font-semibold hover:bg-slate-200 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="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path></svg>
<span x-text="showCharts ? 'Sembunyikan Grafik' : 'Lihat Grafik'"></span>
</button>
<div x-data="{ exportMenuOpen: false }" class="relative">
<button @click="exportMenuOpen = !exportMenuOpen" @click.away="exportMenuOpen = false" class="inline-flex items-center px-4 py-2 bg-emerald-50 text-emerald-700 border border-emerald-200 rounded-lg text-sm font-semibold hover:bg-emerald-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="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"></path></svg>
Export / Import
</button>
<div x-show="exportMenuOpen" x-transition style="display: none;" class="absolute right-0 mt-2 w-48 bg-white border border-slate-100 rounded-xl shadow-xl py-2 z-50">
<a href="{{ route('admin.employees.export.excel', request()->query()) }}" class="flex items-center px-4 py-2 text-sm text-slate-700 hover:bg-slate-50">
<span class="w-2 h-2 rounded-full bg-emerald-500 mr-2"></span> Export to Excel
</a>
<a href="{{ route('admin.employees.export.pdf', request()->query()) }}" target="_blank" class="flex items-center px-4 py-2 text-sm text-slate-700 hover:bg-slate-50">
<span class="w-2 h-2 rounded-full bg-red-500 mr-2"></span> Export to PDF
</a>
<div class="border-t border-slate-100 my-1"></div>
<a href="{{ route('admin.employees.import') }}" class="w-full flex items-center px-4 py-2 text-sm text-slate-700 hover:bg-slate-50 text-left">
<span class="w-2 h-2 rounded-full bg-blue-500 mr-2"></span> Import dari Excel
</a>
</div>
</div>
<a href="{{ route('admin.employees.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 Karyawan
</a>
</div>
</div>
<div x-show="showCharts" x-transition style="display: none;" class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
<div class="bg-white p-5 rounded-2xl border border-slate-200 shadow-sm">
<h3 class="text-sm font-bold text-slate-700 mb-4">Distribusi per Departemen (Geser 👉)</h3>
<div class="overflow-x-auto w-full pb-2 custom-scrollbar">
<div id="deptChartContainer" style="height: 220px;">
<canvas id="deptChart"></canvas>
</div>
</div>
</div>
<div class="bg-white p-5 rounded-2xl border border-slate-200 shadow-sm flex flex-col h-full">
<h3 class="text-sm font-bold text-slate-700 mb-4">Distribusi per Jabatan</h3>
<div class="relative h-40 w-full mb-4">
<canvas id="posChart"></canvas>
</div>
<div class="overflow-x-auto pb-2 custom-scrollbar mt-auto">
<div id="posLegend" class="flex gap-2 whitespace-nowrap min-w-max px-1"></div>
</div>
</div>
</div>
<div class="bg-white p-5 rounded-t-2xl border border-slate-200 border-b-0 relative z-10">
<form action="{{ route('admin.employees.index') }}" method="GET" class="flex flex-col md:flex-row gap-4 items-end">
<div class="w-full md:w-1/3">
<label class="block text-xs font-semibold text-slate-500 mb-1">Pencarian Semua Kolom</label>
<input type="text" name="search" value="{{ request('search') }}" placeholder="Ketik keyword apapun..."
class="w-full px-4 py-2 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:ring-indigo-500">
</div>
<div class="w-full md:w-1/4">
<label class="block text-xs font-semibold text-slate-500 mb-1">Pilih Departemen</label>
<select name="department_id" id="deptSelect" class="select2 w-full">
<option value="">Semua Departemen</option>
@foreach($departments as $dept)
<option value="{{ $dept->id }}" {{ request('department_id') == $dept->id ? 'selected' : '' }}>
{{ $dept->name }}
</option>
@endforeach
</select>
</div>
<div class="w-full md:w-1/4">
<label class="block text-xs font-semibold text-slate-500 mb-1">Pilih Jabatan</label>
<select name="position_id" id="posSelect" class="select2 w-full">
<option value="">Semua Jabatan</option>
</select>
</div>
<div class="w-full md:w-auto flex gap-2">
<button type="submit" class="px-5 py-2 bg-slate-800 text-white rounded-xl text-sm font-semibold hover:bg-slate-700">Filter</button>
@if(request()->hasAny(['search', 'department_id', 'position_id']))
<a href="{{ route('admin.employees.index') }}" class="px-5 py-2 bg-red-50 text-red-600 border border-red-100 rounded-xl text-sm font-semibold hover:bg-red-100">Reset</a>
@endif
</div>
</form>
</div>
<div class="bg-white border border-slate-200 rounded-b-2xl overflow-hidden shadow-sm relative z-0 mt-4 md:mt-0">
<div class="overflow-x-auto custom-scrollbar">
<table class="w-full text-left text-sm whitespace-nowrap">
<thead class="bg-slate-50/80 text-slate-500 text-xs uppercase tracking-wider border-b border-slate-200">
<tr>
<th x-show="showCols.nik" class="px-6 py-4 font-semibold">NIK & Inisial</th>
<th x-show="showCols.name" class="px-6 py-4 font-semibold">Profil & Kontak</th>
<th x-show="showCols.role" class="px-6 py-4 font-semibold text-center">Hak Akses Sistem</th>
<th x-show="showCols.department" class="px-6 py-4 font-semibold">Penempatan</th>
<th x-show="showCols.action" class="px-6 py-4 font-semibold text-right">Opsi</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700">
@forelse($employees as $emp)
<tr class="hover:bg-slate-50">
<td x-show="showCols.nik" class="px-6 py-4">
<div class="font-mono font-bold text-slate-900">{{ $emp->nik ?? '-' }}</div>
<div class="mt-1">
<span class="bg-indigo-50 text-indigo-700 px-2 py-0.5 rounded text-[10px] font-bold border border-indigo-100">
{{ $emp->initial ?? 'N/A' }}
</span>
</div>
</td>
<td x-show="showCols.name" class="px-6 py-4">
<div class="font-bold text-slate-900">
{{ $emp->first_name }} {{ $emp->last_name }}
@if(!$emp->is_active)
<span class="ml-2 px-2 py-0.5 bg-red-100 text-red-600 text-[10px] font-bold rounded uppercase">Non-Aktif</span>
@endif
</div>
<div class="text-xs text-slate-500">{{ $emp->email }}</div>
</td>
<td x-show="showCols.role" class="px-6 py-4 text-center">
<div class="flex flex-wrap gap-1 justify-center">
@php
$isTrainer = $emp->hasRole('trainer') || $emp->is_trainer == 1 || (isset($emp->role) && strtolower($emp->role) == 'trainer');
$isAdmin = $emp->hasRole('admin') || $emp->hasRole('superadmin') || (isset($emp->role) && strtolower($emp->role) == 'admin');
@endphp
@if($isAdmin)
<span class="px-2 py-1 rounded text-[10px] font-bold uppercase tracking-wide bg-red-100 text-red-700">Admin</span>
@endif
@if($isTrainer)
<span class="px-2 py-1 rounded text-[10px] font-bold uppercase tracking-wide bg-amber-100 text-amber-700">Trainer</span>
@endif
<span class="px-2 py-1 rounded text-[10px] font-bold uppercase tracking-wide bg-emerald-100 text-emerald-700">Trainee</span>
</div>
</td>
<td x-show="showCols.department" class="px-6 py-4">
<div class="text-sm font-semibold text-slate-800">{{ $emp->position->name ?? '-' }}</div>
<div class="text-xs text-slate-500 mt-0.5">{{ $emp->department->name ?? '-' }}</div>
</td>
<td x-show="showCols.action" class="px-6 py-4 text-right space-x-2">
<a href="{{ route('admin.employees.show', $emp->id) }}" class="text-slate-400 hover:text-indigo-600 font-medium text-sm">Detail</a>
<a href="{{ route('admin.employees.edit', $emp->id) }}" class="text-indigo-600 hover:text-indigo-800 font-medium text-sm">Edit</a>
<form action="{{ route('admin.employees.destroy', $emp->id) }}" method="POST" class="inline-block" onsubmit="return confirm('Nonaktifkan karyawan ini? Data historis tidak akan dihapus.');">
@csrf @method('DELETE')
<button type="submit" class="text-red-500 hover:text-red-700 font-medium text-sm ml-2">Hapus</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="5" class="px-6 py-10 text-center text-slate-500 italic">Data tidak ditemukan.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@if(method_exists($employees, 'hasPages') && $employees->hasPages())
<div class="p-4 border-t border-slate-100 bg-slate-50/50">
{{ $employees->links() }}
</div>
@endif
</div>
</div>
<script>
$(document).ready(function() {
$('.select2').select2({ width: '100%' });
const mapping = @json($deptPosMapping ?? []);
const posSelect = $('#posSelect');
const deptSelect = $('#deptSelect');
const oldPos = "{{ request('position_id') }}";
function updatePositionDropdown() {
let deptId = deptSelect.val();
posSelect.empty();
posSelect.append(new Option('Semua Jabatan', ''));
if (deptId && mapping[deptId]) {
mapping[deptId].forEach(function(pos) {
let selected = (pos.id == oldPos);
posSelect.append(new Option(pos.name, pos.id, false, selected));
});
} else {
@foreach($positions as $p)
posSelect.append(new Option("{{ $p->name }}", "{{ $p->id }}", false, ("{{ $p->id }}" == oldPos)));
@endforeach
}
posSelect.trigger('change.select2');
}
deptSelect.on('change', updatePositionDropdown);
updatePositionDropdown();
});
// KONFIGURASI GRAFIK
document.addEventListener('DOMContentLoaded', function() {
Chart.register(ChartDataLabels);
const chartColors = ['#4F46E5', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899', '#06B6D4', '#14B8A6', '#F43F5E', '#84CC16', '#3B82F6', '#F97316', '#6366F1'];
const rawDeptData = @json($chartDept ?? []);
const deptLabels = rawDeptData.map(d => d.department ? d.department.name : 'N/A');
const deptCounts = rawDeptData.map(d => d.total);
const deptBgColors = rawDeptData.map((d, i) => chartColors[i % chartColors.length]);
const minDeptWidth = Math.max(600, rawDeptData.length * 60);
document.getElementById('deptChartContainer').style.width = minDeptWidth + 'px';
new Chart(document.getElementById('deptChart'), {
type: 'bar',
data: {
labels: deptLabels,
datasets: [{ data: deptCounts, backgroundColor: deptBgColors, borderRadius: 4 }]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { display: false }, datalabels: { color: '#1e293b', anchor: 'end', align: 'top', font: { weight: 'bold' } } },
scales: { y: { beginAtZero: true, grace: '10%' }, x: { ticks: { autoSkip: false, maxRotation: 45, minRotation: 45 } } }
}
});
const rawPosData = @json($chartPos ?? []);
const posLabels = rawPosData.map(d => d.position ? d.position.name : 'N/A');
const posCounts = rawPosData.map(d => d.total);
const posBgColors = rawPosData.map((d, i) => chartColors[(i + 3) % chartColors.length]);
new Chart(document.getElementById('posChart'), {
type: 'doughnut',
data: { labels: posLabels, datasets: [{ data: posCounts, backgroundColor: posBgColors, borderWidth: 2 }] },
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, datalabels: { display: false } }, cutout: '65%' }
});
const legendContainer = document.getElementById('posLegend');
posLabels.forEach((label, index) => {
const color = posBgColors[index];
const count = posCounts[index];
legendContainer.innerHTML += `<div class="flex items-center text-[11px] text-slate-600 bg-slate-50 px-2.5 py-1.5 rounded-lg border border-slate-200 shadow-sm shrink-0"><span class="w-3 h-3 rounded-full mr-2" style="background-color: ${color}"></span><span class="font-bold text-slate-800 mr-1">${count}</span> ${label}</div>`;
});
});
</script>
<style>
.select2-container .select2-selection--single { height: 38px; border-radius: 0.75rem; 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>
@endsection
@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<head>
<title>Laporan Data Karyawan</title>
<style>
body { font-family: Helvetica, Arial, sans-serif; font-size: 10px; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { border: 1px solid #cbd5e1; padding: 6px; text-align: left; }
th { background-color: #f8fafc; font-weight: bold; text-transform: uppercase; }
.header { border-bottom: 2px solid #334155; padding-bottom: 10px; margin-bottom: 10px; }
.header h2 { margin: 0 0 5px 0; font-size: 18px; color: #1e293b; }
.header p { margin: 2px 0; font-size: 11px; color: #64748b; }
.badge-active { color: #16a34a; font-weight: bold; }
.badge-inactive { color: #dc2626; font-weight: bold; }
</style>
</head>
<body>
<div class="header">
<h2>Laporan Data Karyawan</h2>
<p><b>Total Data:</b> {{ $employees->count() }} Karyawan (Sesuai Filter)</p>
<p><b>Dicetak pada:</b> {{ \Carbon\Carbon::now()->translatedFormat('d F Y - H:i:s') }}</p>
<p><b>Dicetak oleh:</b> {{ auth()->user()->first_name }} {{ auth()->user()->last_name }}</p>
</div>
<table>
<thead>
<tr>
<th width="3%">No</th>
<th width="12%">NIK &amp; Inisial</th>
<th width="20%">Nama Lengkap</th>
<th width="15%">Email</th>
<th width="5%">L/P</th>
<th width="15%">Departemen</th>
<th width="15%">Jabatan</th>
<th width="10%">Status</th>
</tr>
</thead>
<tbody>
@foreach($employees as $index => $emp)
<tr>
<td style="text-align: center;">{{ $index + 1 }}</td>
<td>{{ $emp->nik }} <br> <small>{{ strtoupper($emp->initial ?? '') }}</small></td>
<td>{{ $emp->first_name }} {{ $emp->last_name }}</td>
<td>{{ $emp->email }}</td>
<td style="text-align: center;">{{ $emp->gender }}</td>
<td>{{ $emp->department->name ?? '-' }}</td>
<td>{{ $emp->position->name ?? '-' }}</td>
<td>
<span class="{{ $emp->is_active ? 'badge-active' : 'badge-inactive' }}">
{{ $emp->is_active ? 'Aktif' : 'Non-Aktif' }}
</span>
</td>
</tr>
@endforeach
</tbody>
</table>
</body>
</html>
@@ -0,0 +1,127 @@
@extends('layouts.app')
@section('content')
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<!-- HEADER & TOMBOL AKSI -->
<div class="mb-6 flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div class="flex items-center space-x-3">
<a href="{{ route('admin.employees.index') }}" class="text-slate-400 hover:text-blue-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Profil Karyawan</h2>
</div>
<div class="flex space-x-3">
<a href="{{ route('admin.employees.edit', $employee->id) }}" class="px-4 py-2 bg-white border border-slate-200 text-slate-700 rounded-lg text-sm font-semibold hover:bg-slate-50 flex items-center shadow-sm">
<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="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>
Edit Data
</a>
<form action="{{ route('admin.employees.destroy', $employee->id) }}" method="POST" onsubmit="return confirm('Apakah Anda yakin ingin menghapus karyawan ini secara permanen?');">
@csrf @method('DELETE')
<button type="submit" class="px-4 py-2 bg-red-50 text-red-600 border border-red-100 rounded-lg text-sm font-semibold hover:bg-red-100 flex items-center shadow-sm">
Hapus
</button>
</form>
</div>
</div>
<!-- KARTU PROFIL UTAMA -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden mb-6">
<div class="bg-gradient-to-r from-blue-600 to-indigo-700 h-24 sm:h-32"></div>
<div class="px-6 sm:px-8 pb-8 relative">
<div class="-mt-12 sm:-mt-16 flex justify-between items-end mb-4">
<!-- Avatar Inisial -->
<div class="w-24 h-24 sm:w-32 sm:h-32 bg-white rounded-full p-1.5 shadow-lg">
<div class="w-full h-full bg-blue-100 rounded-full flex items-center justify-center text-blue-700 text-3xl font-bold border-2 border-blue-200">
{{ strtoupper(substr($employee->first_name, 0, 1)) }}{{ $employee->last_name ? strtoupper(substr($employee->last_name, 0, 1)) : '' }}
</div>
</div>
<!-- Status Role Spatie -->
<div class="mb-2">
@foreach($employee->roles as $role)
<span class="px-3 py-1 text-xs font-bold rounded-full bg-slate-900 text-white uppercase tracking-wider shadow-sm">
Role: {{ $role->name }}
</span>
@endforeach
</div>
</div>
<div>
<h1 class="text-2xl font-extrabold text-slate-900">{{ $employee->first_name }} {{ $employee->last_name }}</h1>
<p class="text-slate-500 font-medium">NIK: <span class="text-slate-800">{{ $employee->nik }}</span></p>
</div>
</div>
</div>
<!-- DETAIL INFORMASI -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Kolom Kiri: Info Pekerjaan -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 p-6">
<h3 class="text-sm font-bold text-slate-800 uppercase tracking-wider mb-4 pb-2 border-b border-slate-100">Informasi Pekerjaan</h3>
<dl class="space-y-4">
<div>
<dt class="text-xs font-semibold text-slate-500">Departemen</dt>
<dd class="text-sm font-bold text-indigo-700 mt-1">{{ $employee->department->name ?? 'Belum ditentukan' }}</dd>
</div>
<div>
<dt class="text-xs font-semibold text-slate-500">Posisi / Jabatan</dt>
<dd class="text-sm font-bold text-slate-900 mt-1">{{ $employee->position->name ?? 'Belum ditentukan' }}</dd>
</div>
<div>
<dt class="text-xs font-semibold text-slate-500">Tanggal Bergabung</dt>
<dd class="text-sm font-bold text-slate-900 mt-1">{{ $employee->join_date ? $employee->join_date->translatedFormat('d F Y') : '-' }}</dd>
</div>
<div>
<dt class="text-xs font-semibold text-slate-500">Matrix Training Utama</dt>
<dd class="text-sm font-bold text-slate-900 mt-1">
@if($employee->training_matrix_id)
<span class="inline-flex items-center px-2.5 py-0.5 rounded-md text-xs font-medium bg-emerald-100 text-emerald-800">
Matriks Tersedia (ID: {{ $employee->training_matrix_id }})
</span>
@else
<span class="text-slate-400 italic">Belum dikaitkan ke matriks</span>
@endif
</dd>
</div>
</dl>
</div>
<!-- Kolom Kanan: Info Personal -->
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 p-6">
<h3 class="text-sm font-bold text-slate-800 uppercase tracking-wider mb-4 pb-2 border-b border-slate-100">Informasi Personal & Kontak</h3>
<dl class="space-y-4 grid grid-cols-2 gap-x-4">
<div class="col-span-2">
<dt class="text-xs font-semibold text-slate-500">Email Perusahaan</dt>
<dd class="text-sm font-bold text-blue-600 mt-1">{{ $employee->email }}</dd>
</div>
<div>
<dt class="text-xs font-semibold text-slate-500">No. HP / Telepon</dt>
<dd class="text-sm font-bold text-slate-900 mt-1">{{ $employee->phone ?? '-' }}</dd>
</div>
<div>
<dt class="text-xs font-semibold text-slate-500">Nomor KTP</dt>
<dd class="text-sm font-bold text-slate-900 mt-1">{{ $employee->identity_number ?? '-' }}</dd>
</div>
<div>
<dt class="text-xs font-semibold text-slate-500">Jenis Kelamin</dt>
<dd class="text-sm font-bold text-slate-900 mt-1">
{{ $employee->gender == 'L' ? 'Laki-laki' : ($employee->gender == 'P' ? 'Perempuan' : '-') }}
</dd>
</div>
<div>
<dt class="text-xs font-semibold text-slate-500">Tanggal Lahir</dt>
<dd class="text-sm font-bold text-slate-900 mt-1">{{ $employee->date_of_birth ? $employee->date_of_birth->translatedFormat('d F Y') : '-' }}</dd>
</div>
<div>
<dt class="text-xs font-semibold text-slate-500">Inisial Nama</dt>
<dd class="text-sm font-bold text-slate-900 mt-1 uppercase">{{ $employee->initial ?? '-' }}</dd>
</div>
</dl>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,145 @@
@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: 42px; border-radius: 0.75rem; border-color: #e2e8f0; background-color: #f8fafc; }
.select2-container--default .select2-selection--single .select2-selection__rendered { line-height: 42px; font-size: 0.875rem; color: #334155; padding-left: 1rem; }
.select2-container--default .select2-selection--single .select2-selection__arrow { height: 40px; right: 10px; }
</style>
<div class="max-w-5xl mx-auto px-4 py-8" x-data="{ questionType: '{{ old('type', '') }}' }">
<div class="mb-6 flex items-center space-x-3">
<a href="{{ route('admin.exams.questions') }}" class="text-slate-400 hover:text-blue-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Tambah Soal Baru</h2>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
<form action="{{ url('admin/exams/questions') }}" method="POST" enctype="multipart/form-data" class="p-6 sm:p-8 space-y-6">
@csrf
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Departemen</label>
<select name="department_id" class="select2 w-full text-sm">
<option value="">-- Berlaku untuk Semua Departemen --</option>
@foreach($departments as $dept)
<option value="{{ $dept->id }}" {{ old('department_id') == $dept->id ? 'selected' : '' }}>{{ $dept->name }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Posisi / Jabatan</label>
<select name="position_id" class="select2 w-full text-sm">
<option value="">-- Berlaku untuk Semua Jabatan --</option>
@foreach($positions as $pos)
<option value="{{ $pos->id }}" {{ old('position_id') == $pos->id ? 'selected' : '' }}>{{ $pos->name }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Materi SOP / Modul <span class="text-red-500">*</span></label>
<select name="training_matrix_id" class="select2 w-full text-sm" required>
<option value="">-- Pilih Materi Pembelajaran --</option>
@foreach($matrices as $matrix)
<option value="{{ $matrix->id }}" {{ old('training_matrix_id') == $matrix->id ? 'selected' : '' }}>{{ $matrix->title }}</option>
@endforeach
</select>
</div>
<div class="lg:col-span-2">
<label class="block text-sm font-bold text-slate-700 mb-2">Tipe Soal <span class="text-red-500">*</span></label>
<select name="type" x-model="questionType" class="select2 w-full text-sm" required>
<option value="">-- Pilih Tipe Pertanyaan --</option>
<option value="single">Single Choice (Satu Jawaban Benar)</option>
<option value="multiple">Multiple Choice (Banyak Jawaban Benar)</option>
<option value="true_false">True / False (Benar / Salah)</option>
<option value="descriptive">Descriptive (Esai / Uraian)</option>
</select>
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Tingkat Kesulitan <span class="text-red-500">*</span></label>
<select name="level" class="select2 w-full text-sm" required>
<option value="mudah" {{ old('level') == 'mudah' ? 'selected' : '' }}>Mudah (Easy)</option>
<option value="sedang" {{ old('level') == 'sedang' ? 'selected' : '' }}>Sedang (Medium)</option>
<option value="sulit" {{ old('level') == 'sulit' ? 'selected' : '' }}>Sulit (Hard)</option>
</select>
</div>
</div>
<div class="border-t border-slate-100 pt-6">
<label class="block text-sm font-bold text-slate-700 mb-2">Pertanyaan <span class="text-red-500">*</span></label>
<textarea name="question_text" rows="4" required class="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-blue-500/20 focus:border-blue-600 transition-all text-sm" placeholder="Tuliskan pertanyaan di sini...">{{ old('question_text') }}</textarea>
</div>
<div class="border-t border-slate-100 pt-6" x-show="questionType !== ''" x-transition>
<h3 class="text-sm font-bold text-slate-800 uppercase tracking-wider mb-4 border-l-4 border-blue-500 pl-3">Pengaturan Jawaban</h3>
<div x-show="questionType === 'single'" style="display: none;" class="space-y-3">
<p class="text-xs text-slate-500 mb-3">Pilih satu radio button sebagai jawaban yang benar.</p>
@foreach(['A', 'B', 'C', 'D'] as $opt)
<div class="flex items-center gap-3">
<input type="radio" name="correct_answer" value="{{ $opt }}" class="w-5 h-5 text-blue-600 border-slate-300 focus:ring-blue-500 cursor-pointer">
<input type="text" name="options[{{ $opt }}]" placeholder="Opsi Jawaban {{ $opt }}" class="flex-1 px-4 py-2 bg-white border border-slate-200 rounded-lg text-sm focus:border-blue-500">
</div>
@endforeach
</div>
<div x-show="questionType === 'multiple'" style="display: none;" class="space-y-3">
<p class="text-xs text-slate-500 mb-3">Centang lebih dari satu checkbox untuk jawaban yang benar.</p>
@foreach(['A', 'B', 'C', 'D', 'E'] as $opt)
<div class="flex items-center gap-3">
<input type="checkbox" name="correct_answers[]" value="{{ $opt }}" class="w-5 h-5 text-blue-600 border-slate-300 rounded focus:ring-blue-500 cursor-pointer">
<input type="text" name="options[{{ $opt }}]" placeholder="Opsi Jawaban {{ $opt }}" class="flex-1 px-4 py-2 bg-white border border-slate-200 rounded-lg text-sm focus:border-blue-500">
</div>
@endforeach
</div>
<div x-show="questionType === 'true_false'" style="display: none;" class="flex gap-6">
<label class="flex items-center gap-2 p-4 border border-slate-200 rounded-xl cursor-pointer hover:bg-slate-50 w-48">
<input type="radio" name="correct_answer" value="true" class="w-5 h-5 text-emerald-600 border-slate-300 focus:ring-emerald-500">
<span class="font-bold text-slate-700">True (Benar)</span>
</label>
<label class="flex items-center gap-2 p-4 border border-slate-200 rounded-xl cursor-pointer hover:bg-slate-50 w-48">
<input type="radio" name="correct_answer" value="false" class="w-5 h-5 text-red-600 border-slate-300 focus:ring-red-500">
<span class="font-bold text-slate-700">False (Salah)</span>
</label>
</div>
<div x-show="questionType === 'descriptive'" style="display: none;">
<p class="text-xs text-slate-500 mb-3">Tuliskan kata kunci / panduan jawaban benar untuk penilai (Opsional).</p>
<textarea name="expected_answer" rows="3" class="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:border-blue-500" placeholder="Kata kunci jawaban..."></textarea>
</div>
</div>
<div class="pt-6 flex justify-end space-x-3 border-t border-slate-100 mt-8">
<a href="{{ route('admin.exams.questions') }}" class="px-5 py-2.5 text-sm font-semibold text-slate-600 hover:bg-slate-100 rounded-xl transition-colors">Batal</a>
<button type="submit" class="px-5 py-2.5 text-sm font-semibold text-white bg-blue-600 hover:bg-blue-700 rounded-xl shadow-md transition-all">Simpan Soal</button>
</div>
</form>
</div>
</div>
<script>
$(document).ready(function() {
$('.select2').select2({ width: '100%' });
// Menjembatani Select2 dengan Alpine.js agar x-model ter-update saat Select2 berubah
$('select[name="type"]').on('change', function() {
// Ambil elemen div pembungkus Alpine (x-data) dan ubah nilainya
let el = document.querySelector('[x-data]');
if(el && el.__x) {
el.__x.$data.questionType = $(this).val();
} else {
// Alternatif dispatch event custom jika pakai versi Alpine V3 terbaru
el.dispatchEvent(new CustomEvent('update-type', { detail: $(this).val() }));
}
});
});
</script>
@endsection
@@ -0,0 +1,101 @@
@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: 42px; border-radius: 0.75rem; border-color: #e2e8f0; background-color: #f8fafc; }
.select2-container--default .select2-selection--single .select2-selection__rendered { line-height: 42px; font-size: 0.875rem; color: #334155; padding-left: 1rem; }
.select2-container--default .select2-selection--single .select2-selection__arrow { height: 40px; right: 10px; }
</style>
<div class="max-w-5xl mx-auto px-4 py-8" x-data="{ questionType: '{{ old('type', $question->type) }}' }" @update-type.window="questionType = $event.detail">
<div class="mb-6 flex items-center space-x-3">
<a href="{{ route('admin.exams.questions') }}" class="text-slate-400 hover:text-blue-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Edit Soal: #{{ $question->id }}</h2>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
<form action="{{ url('admin/exams/questions/' . $question->id) }}" method="POST" class="p-6 sm:p-8 space-y-6">
@csrf @method('PUT')
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Departemen</label>
<select name="department_id" class="select2 w-full text-sm">
<option value="">-- Semua Departemen --</option>
@foreach($departments as $dept)
<option value="{{ $dept->id }}" {{ old('department_id', $question->department_id) == $dept->id ? 'selected' : '' }}>{{ $dept->name }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Posisi / Jabatan</label>
<select name="position_id" class="select2 w-full text-sm">
<option value="">-- Semua Jabatan --</option>
@foreach($positions as $pos)
<option value="{{ $pos->id }}" {{ old('position_id', $question->position_id) == $pos->id ? 'selected' : '' }}>{{ $pos->name }}</option>
@endforeach
</select>
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Materi SOP / Modul <span class="text-red-500">*</span></label>
<select name="training_matrix_id" class="select2 w-full text-sm" required>
<option value="">-- Pilih Materi Pembelajaran --</option>
@foreach($matrices as $matrix)
<option value="{{ $matrix->id }}" {{ old('training_matrix_id', $question->training_matrix_id) == $matrix->id ? 'selected' : '' }}>{{ $matrix->title }}</option>
@endforeach
</select>
</div>
<div class="lg:col-span-2">
<label class="block text-sm font-bold text-slate-700 mb-2">Tipe Soal <span class="text-red-500">*</span></label>
<select name="type" class="select2 w-full text-sm" required>
<option value="single" {{ $question->type == 'single' ? 'selected' : '' }}>Single Choice (Satu Jawaban Benar)</option>
<option value="multiple" {{ $question->type == 'multiple' ? 'selected' : '' }}>Multiple Choice (Banyak Jawaban Benar)</option>
<option value="true_false" {{ $question->type == 'true_false' ? 'selected' : '' }}>True / False (Benar / Salah)</option>
<option value="descriptive" {{ $question->type == 'descriptive' ? 'selected' : '' }}>Descriptive (Esai / Uraian)</option>
</select>
</div>
<div>
<label class="block text-sm font-bold text-slate-700 mb-2">Tingkat Kesulitan <span class="text-red-500">*</span></label>
<select name="level" class="select2 w-full text-sm" required>
<option value="mudah" {{ $question->level == 'mudah' ? 'selected' : '' }}>Mudah (Easy)</option>
<option value="sedang" {{ $question->level == 'sedang' ? 'selected' : '' }}>Sedang (Medium)</option>
<option value="sulit" {{ $question->level == 'sulit' ? 'selected' : '' }}>Sulit (Hard)</option>
</select>
</div>
</div>
<div class="border-t border-slate-100 pt-6">
<label class="block text-sm font-bold text-slate-700 mb-2">Pertanyaan <span class="text-red-500">*</span></label>
<textarea name="question_text" rows="4" required class="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:border-blue-500">{{ old('question_text', $question->question_text) }}</textarea>
</div>
<div class="bg-amber-50 border-l-4 border-amber-500 p-4 mt-4">
<p class="text-sm text-amber-800 font-semibold">Tipe Soal diubah?</p>
<p class="text-xs text-amber-700 mt-1">Jika Anda mengubah tipe soal, pastikan Anda mengisi kembali opsi jawabannya di bawah ini karena format jawabannya berubah.</p>
</div>
<div class="pt-6 flex justify-end space-x-3 border-t border-slate-100 mt-8">
<a href="{{ route('admin.exams.questions') }}" class="px-5 py-2.5 text-sm font-semibold text-slate-600 hover:bg-slate-100 rounded-xl transition-colors">Batal</a>
<button type="submit" class="px-5 py-2.5 text-sm font-semibold text-white bg-blue-600 hover:bg-blue-700 rounded-xl shadow-md transition-all">Perbarui Soal</button>
</div>
</form>
</div>
</div>
<script>
$(document).ready(function() {
$('.select2').select2({ width: '100%' });
$('select[name="type"]').on('change', function() {
window.dispatchEvent(new CustomEvent('update-type', { detail: $(this).val() }));
});
});
</script>
@endsection
@@ -0,0 +1,217 @@
@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
@@ -0,0 +1,74 @@
@extends('layouts.app')
@section('content')
<div class="max-w-4xl mx-auto px-4 py-8">
<div class="flex items-center justify-between mb-6">
<div class="flex items-center space-x-3">
<a href="{{ route('admin.exams.questions') }}" class="text-slate-400 hover:text-blue-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Detail Pertanyaan</h2>
</div>
<a href="{{ url('admin/exams/questions/'.$question->id.'/edit') }}" class="px-4 py-2 bg-blue-50 text-blue-700 rounded-lg text-sm font-bold hover:bg-blue-100 transition-colors">
Edit Soal
</a>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 p-6 mb-6">
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div>
<span class="block text-xs font-semibold text-slate-400 uppercase">Q.ID</span>
<span class="block text-sm font-mono font-bold text-slate-900">#{{ $question->id }}</span>
</div>
<div>
<span class="block text-xs font-semibold text-slate-400 uppercase">Materi SOP</span>
<span class="block text-sm font-medium text-slate-900">{{ $question->matrix->title ?? 'Umum' }}</span>
</div>
<div>
<span class="block text-xs font-semibold text-slate-400 uppercase">Tipe Soal</span>
<span class="inline-block mt-1 px-2 py-0.5 bg-indigo-50 text-indigo-700 rounded text-[10px] font-bold uppercase border border-indigo-100">
{{ str_replace('_', ' ', $question->type) }}
</span>
</div>
<div>
<span class="block text-xs font-semibold text-slate-400 uppercase">Level</span>
<span class="block text-sm font-bold mt-1 {{ $question->level == 'mudah' ? 'text-emerald-500' : ($question->level == 'sedang' ? 'text-amber-500' : 'text-red-500') }}">
{{ strtoupper($question->level) }}
</span>
</div>
</div>
<div class="border-t border-slate-100 mt-4 pt-4 flex gap-6">
<div>
<span class="block text-xs font-semibold text-slate-400 uppercase">Dikhususkan untuk Departemen:</span>
<span class="block text-sm text-slate-700">{{ $question->department->name ?? 'Semua Departemen' }}</span>
</div>
<div>
<span class="block text-xs font-semibold text-slate-400 uppercase">Dikhususkan untuk Jabatan:</span>
<span class="block text-sm text-slate-700">{{ $question->position->name ?? 'Semua Jabatan' }}</span>
</div>
</div>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 p-6 sm:p-8">
<h4 class="text-sm font-bold text-slate-400 uppercase tracking-wider mb-4 border-b border-slate-100 pb-2">Isi Pertanyaan</h4>
<div class="prose prose-slate max-w-none text-slate-800 text-lg mb-8">
{!! nl2br(e($question->question_text)) !!}
</div>
<h4 class="text-sm font-bold text-slate-400 uppercase tracking-wider mb-4 border-b border-slate-100 pb-2">Opsi Jawaban & Kunci</h4>
<div class="space-y-3">
@if($question->type === 'descriptive')
<div class="p-4 bg-slate-50 border border-slate-200 rounded-xl">
<span class="text-xs font-bold text-slate-500 uppercase">Kunci / Panduan Penilaian:</span>
<p class="text-slate-800 mt-2">{{ $question->expected_answer ?? 'Tidak ada kata kunci khusus yang diatur.' }}</p>
</div>
@else
<p class="italic text-sm text-slate-500">Tampilan opsi jawaban disesuaikan dengan struktur relasi database opsi Anda.</p>
@endif
</div>
</div>
</div>
@endsection
@@ -0,0 +1,96 @@
@extends('layouts.app') @section('content')
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div class="flex justify-between items-center mb-8">
<div>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Manajemen Master Data</h2>
<p class="text-sm text-slate-500 mt-1">Kelola data Departemen dan Posisi (Jabatan) untuk struktur organisasi perusahaan.</p>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden flex flex-col">
<div class="p-5 border-b border-slate-100 flex justify-between items-center bg-slate-50/50">
<h3 class="text-lg font-bold text-slate-800 flex items-center">
<svg class="w-5 h-5 mr-2 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"></path></svg>
Daftar Departemen
</h3>
<button class="bg-indigo-50 text-indigo-600 hover:bg-indigo-100 px-3 py-1.5 rounded-lg text-sm font-semibold transition-colors">
+ Tambah Baru
</button>
</div>
<div class="flex-1 p-0 overflow-x-auto">
<table class="w-full text-left text-sm whitespace-nowrap">
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wider">
<tr>
<th class="px-5 py-3 font-semibold">ID</th>
<th class="px-5 py-3 font-semibold">Nama Departemen</th>
<th class="px-5 py-3 font-semibold text-right">Aksi</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700">
<tr class="hover:bg-slate-50 transition-colors">
<td class="px-5 py-4 font-medium text-slate-900">1</td>
<td class="px-5 py-4">Quality Assurance (QA)</td>
<td class="px-5 py-4 text-right">
<button class="text-indigo-600 hover:text-indigo-800 font-medium text-sm mr-3">Edit</button>
<button class="text-red-500 hover:text-red-700 font-medium text-sm">Hapus</button>
</td>
</tr>
<tr class="hover:bg-slate-50 transition-colors">
<td class="px-5 py-4 font-medium text-slate-900">2</td>
<td class="px-5 py-4">Produksi Farmasi</td>
<td class="px-5 py-4 text-right">
<button class="text-indigo-600 hover:text-indigo-800 font-medium text-sm mr-3">Edit</button>
<button class="text-red-500 hover:text-red-700 font-medium text-sm">Hapus</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden flex flex-col">
<div class="p-5 border-b border-slate-100 flex justify-between items-center bg-slate-50/50">
<h3 class="text-lg font-bold text-slate-800 flex items-center">
<svg class="w-5 h-5 mr-2 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path></svg>
Daftar Posisi
</h3>
<button class="bg-emerald-50 text-emerald-600 hover:bg-emerald-100 px-3 py-1.5 rounded-lg text-sm font-semibold transition-colors">
+ Tambah Baru
</button>
</div>
<div class="flex-1 p-0 overflow-x-auto">
<table class="w-full text-left text-sm whitespace-nowrap">
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wider">
<tr>
<th class="px-5 py-3 font-semibold">ID</th>
<th class="px-5 py-3 font-semibold">Nama Posisi</th>
<th class="px-5 py-3 font-semibold text-right">Aksi</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700">
<tr class="hover:bg-slate-50 transition-colors">
<td class="px-5 py-4 font-medium text-slate-900">1</td>
<td class="px-5 py-4">Manager</td>
<td class="px-5 py-4 text-right">
<button class="text-indigo-600 hover:text-indigo-800 font-medium text-sm mr-3">Edit</button>
<button class="text-red-500 hover:text-red-700 font-medium text-sm">Hapus</button>
</td>
</tr>
<tr class="hover:bg-slate-50 transition-colors">
<td class="px-5 py-4 font-medium text-slate-900">2</td>
<td class="px-5 py-4">Supervisor QA</td>
<td class="px-5 py-4 text-right">
<button class="text-indigo-600 hover:text-indigo-800 font-medium text-sm mr-3">Edit</button>
<button class="text-red-500 hover:text-red-700 font-medium text-sm">Hapus</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,41 @@
@extends('layouts.app')
@section('content')
<div class="max-w-3xl mx-auto px-4 py-8">
<div class="mb-6 flex items-center space-x-3">
<a href="{{ route('admin.positions.index') }}" class="text-slate-400 hover:text-emerald-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Tambah Posisi/Jabatan Baru</h2>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
<form action="{{ route('admin.positions.store') }}" method="POST" class="p-6 sm:p-8 space-y-6">
@csrf
<div>
<label for="department_id" class="block text-sm font-bold text-slate-700 mb-2">Departemen Induk <span class="text-red-500">*</span></label>
<select name="department_id" id="department_id" required class="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-600 transition-all">
<option value="">-- Pilih Departemen --</option>
@foreach($departments as $dept)
<option value="{{ $dept->id }}" {{ old('department_id') == $dept->id ? 'selected' : '' }}>{{ $dept->name }}</option>
@endforeach
</select>
@error('department_id') <span class="text-xs text-red-500 mt-1 block">{{ $message }}</span> @enderror
</div>
<div>
<label for="name" class="block text-sm font-bold text-slate-700 mb-2">Nama Posisi <span class="text-red-500">*</span></label>
<input type="text" name="name" id="name" value="{{ old('name') }}" required placeholder="Contoh: Manager Produksi"
class="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-600 transition-all">
@error('name') <span class="text-xs text-red-500 mt-1 block">{{ $message }}</span> @enderror
</div>
<div class="pt-4 flex justify-end space-x-3 border-t border-slate-100">
<a href="{{ route('admin.positions.index') }}" class="px-5 py-2.5 text-sm font-semibold text-slate-600 hover:bg-slate-100 rounded-xl transition-colors">Batal</a>
<button type="submit" class="px-5 py-2.5 text-sm font-semibold text-white bg-emerald-600 hover:bg-emerald-700 rounded-xl shadow-md transition-all">Simpan Posisi</button>
</div>
</form>
</div>
</div>
@endsection
@@ -0,0 +1,42 @@
@extends('layouts.app')
@section('content')
<div class="max-w-3xl mx-auto px-4 py-8">
<div class="mb-6 flex items-center space-x-3">
<a href="{{ route('admin.positions.index') }}" class="text-slate-400 hover:text-emerald-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Edit Posisi / Jabatan</h2>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
<form action="{{ route('admin.positions.update', $position->id) }}" method="POST" class="p-6 sm:p-8 space-y-6">
@csrf
@method('PUT') <div>
<label for="department_id" class="block text-sm font-bold text-slate-700 mb-2">Departemen Induk <span class="text-red-500">*</span></label>
<select name="department_id" id="department_id" required class="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-600 transition-all">
<option value="">-- Pilih Departemen --</option>
@foreach($departments as $dept)
<option value="{{ $dept->id }}" {{ old('department_id', $position->department_id) == $dept->id ? 'selected' : '' }}>
{{ $dept->name }}
</option>
@endforeach
</select>
@error('department_id') <span class="text-xs text-red-500 mt-1 block">{{ $message }}</span> @enderror
</div>
<div>
<label for="name" class="block text-sm font-bold text-slate-700 mb-2">Nama Posisi <span class="text-red-500">*</span></label>
<input type="text" name="name" id="name" value="{{ old('name', $position->name) }}" required placeholder="Contoh: Manager Produksi"
class="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:ring-2 focus:ring-emerald-500/20 focus:border-emerald-600 transition-all">
@error('name') <span class="text-xs text-red-500 mt-1 block">{{ $message }}</span> @enderror
</div>
<div class="pt-4 flex justify-end space-x-3 border-t border-slate-100">
<a href="{{ route('admin.positions.index') }}" class="px-5 py-2.5 text-sm font-semibold text-slate-600 hover:bg-slate-100 rounded-xl transition-colors">Batal</a>
<button type="submit" class="px-5 py-2.5 text-sm font-semibold text-white bg-emerald-600 hover:bg-emerald-700 rounded-xl shadow-md transition-all">Perbarui Posisi</button>
</div>
</form>
</div>
</div>
@endsection
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<title>Master Data Jabatan</title>
<style>
body { font-family: Helvetica, Arial, sans-serif; font-size: 12px; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { border: 1px solid #cbd5e1; padding: 8px; text-align: left; }
th { background-color: #f8fafc; font-weight: bold; text-transform: uppercase; }
.header { border-bottom: 2px solid #334155; padding-bottom: 10px; margin-bottom: 10px; }
.header h2 { margin: 0 0 5px 0; font-size: 18px; color: #1e293b; }
.header p { margin: 2px 0; font-size: 12px; color: #64748b; }
</style>
</head>
<body>
<div class="header">
<h2>Laporan Master Data Jabatan</h2>
<p><b>Total Data:</b> {{ $positions->count() }} Jabatan</p>
<p><b>Dicetak pada:</b> {{ \Carbon\Carbon::now()->translatedFormat('d F Y - H:i:s') }}</p>
<p><b>Dicetak oleh:</b> {{ auth()->user()->first_name }} {{ auth()->user()->last_name }}</p>
</div>
<table>
<thead>
<tr>
<th width="10%" style="text-align: center;">No</th>
<th width="60%">Nama Jabatan / Posisi</th>
<th width="30%">Tanggal Dibuat</th>
</tr>
</thead>
<tbody>
@foreach($positions as $index => $pos)
<tr>
<td style="text-align: center;">{{ $index + 1 }}</td>
<td>{{ $pos->name }}</td>
<td>{{ $pos->created_at ? \Carbon\Carbon::parse($pos->created_at)->format('d-m-Y H:i') : '-' }}</td>
</tr>
@endforeach
</tbody>
</table>
</body>
</html>
@@ -0,0 +1,107 @@
@extends('layouts.app')
@section('content')
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"
x-data="{
showCols: { id: true, name: true, action: true },
exportOpen: false,
columnOpen: false
}">
<div class="flex flex-col md:flex-row md:items-center justify-between mb-8 gap-4">
<div>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Manajemen Posisi / Jabatan</h2>
<p class="text-sm text-slate-500 mt-1">Total <span class="font-bold text-indigo-600">{{ $positions instanceof \Illuminate\Contracts\Pagination\LengthAwarePaginator ? $positions->total() : $positions->count() }}</span> rekor ditemukan.</p>
</div>
<a href="{{ route('admin.positions.create') }}" class="inline-flex items-center justify-center px-4 py-2 bg-indigo-600 text-white rounded-lg text-sm font-semibold hover:bg-indigo-700 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="M12 4v16m8-8H4"></path></svg>
Tambah Posisi
</a>
</div>
<div class="bg-white p-4 rounded-t-2xl border border-slate-200 border-b-0 flex flex-col md:flex-row gap-4 justify-between items-center relative z-10">
<form action="{{ route('admin.positions.index') }}" method="GET" class="w-full md:w-96 relative">
<input type="text" name="search" value="{{ request('search') }}" placeholder="Cari nama jabatan..."
class="w-full pl-10 pr-4 py-2 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-600 transition-all">
<svg class="w-4 h-4 text-slate-400 absolute left-3.5 top-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
@if(request('search'))
<a href="{{ route('admin.positions.index') }}" class="absolute right-3 top-2.5 text-xs text-red-500 hover:underline">Clear</a>
@endif
</form>
<div class="flex items-center space-x-3 w-full md:w-auto">
<div class="relative">
<button @click="columnOpen = !columnOpen" @click.away="columnOpen = false" class="px-4 py-2 bg-white border border-slate-200 text-slate-700 rounded-xl text-sm font-semibold hover:bg-slate-50 flex items-center shadow-sm">
<svg class="w-4 h-4 mr-2 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2"></path></svg>
Kolom
</button>
<div x-show="columnOpen" x-transition class="absolute right-0 mt-2 w-48 bg-white border border-slate-100 rounded-xl shadow-xl py-2 z-50" style="display: none;">
<label class="flex items-center px-4 py-2 hover:bg-slate-50 cursor-pointer text-sm"><input type="checkbox" x-model="showCols.id" class="rounded border-slate-300 text-indigo-600 mr-3"> ID</label>
<label class="flex items-center px-4 py-2 hover:bg-slate-50 cursor-pointer text-sm"><input type="checkbox" x-model="showCols.name" class="rounded border-slate-300 text-indigo-600 mr-3"> Nama Posisi</label>
</div>
</div>
<div class="relative">
<button @click="exportOpen = !exportOpen" @click.away="exportOpen = false" class="px-4 py-2 bg-emerald-50 border border-emerald-200 text-emerald-700 rounded-xl text-sm font-semibold hover:bg-emerald-100 flex items-center 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-4l-4 4m0 0l-4-4m4 4V4"></path></svg>
Export Data
</button>
<div x-show="exportOpen" x-transition class="absolute right-0 mt-2 w-48 bg-white border border-slate-100 rounded-xl shadow-xl py-2 z-50" style="display: none;">
<p class="px-4 py-1 text-[10px] font-bold text-slate-400 uppercase tracking-wider">Pilih Format</p>
<a href="{{ url('admin/positions/export/excel?search=' . request('search')) }}" class="flex items-center px-4 py-2 hover:bg-slate-50 text-sm text-slate-700">
<span class="w-2 h-2 rounded-full bg-emerald-500 mr-2"></span> Excel (.xlsx)
</a>
<a href="{{ url('admin/positions/export/pdf?search=' . request('search')) }}" class="flex items-center px-4 py-2 hover:bg-slate-50 text-sm text-slate-700">
<span class="w-2 h-2 rounded-full bg-red-500 mr-2"></span> PDF (.pdf)
</a>
</div>
</div>
</div>
</div>
<div class="bg-white border border-slate-200 rounded-b-2xl overflow-hidden shadow-sm relative z-0">
<div class="overflow-x-auto">
<table class="w-full text-left text-sm whitespace-nowrap">
<thead class="bg-slate-50/80 text-slate-500 text-xs uppercase tracking-wider border-b border-slate-200">
<tr>
<th x-show="showCols.id" class="px-6 py-4 font-semibold">ID</th>
<th x-show="showCols.name" class="px-6 py-4 font-semibold">Nama Posisi</th>
<th x-show="showCols.action" class="px-6 py-4 font-semibold text-right">Aksi</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700">
@forelse($positions as $pos)
<tr class="hover:bg-slate-50 transition-colors">
<td x-show="showCols.id" class="px-6 py-4 font-medium text-slate-500">#{{ $pos->id }}</td>
<td x-show="showCols.name" class="px-6 py-4 font-bold text-slate-900">{{ $pos->name }}</td>
<td x-show="showCols.action" class="px-6 py-4 text-right space-x-3">
<a href="{{ route('admin.positions.show', $pos->id) }}" class="text-slate-400 hover:text-indigo-600 font-medium text-sm transition-colors">Detail</a>
<a href="{{ route('admin.positions.edit', $pos->id) }}" class="text-indigo-600 hover:text-indigo-800 font-medium text-sm transition-colors">Edit</a>
<form action="{{ route('admin.positions.destroy', $pos->id) }}" method="POST" class="inline-block" onsubmit="return confirm('Apakah Anda yakin ingin menghapus posisi ini?');">
@csrf @method('DELETE')
<button type="submit" class="text-red-500 hover:text-red-700 font-medium text-sm transition-colors">Hapus</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="3" class="px-6 py-12 text-center text-slate-500">
<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="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"></path></svg>
Tidak ada data posisi yang ditemukan.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@if(method_exists($positions, 'hasPages') && $positions->hasPages())
<div class="p-4 border-t border-slate-100 bg-slate-50/50">
{{ $positions->links() }}
</div>
@endif
</div>
</div>
@endsection
@@ -0,0 +1,56 @@
@extends('layouts.app')
@section('content')
<div class="max-w-4xl mx-auto px-4 py-8">
<div class="mb-6 flex items-center justify-between">
<div class="flex items-center space-x-3">
<a href="{{ route('admin.positions.index') }}" class="text-slate-400 hover:text-emerald-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Detail Posisi / Jabatan</h2>
</div>
<a href="{{ route('admin.positions.edit', $position->id) }}" class="px-4 py-2 bg-emerald-50 text-emerald-700 hover:bg-emerald-100 rounded-lg text-sm font-bold transition-all">
Edit Data
</a>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 p-8 mb-8 relative overflow-hidden">
<div class="absolute top-0 right-0 w-32 h-32 bg-emerald-50 rounded-bl-full -mr-8 -mt-8 opacity-50 pointer-events-none"></div>
<div class="flex flex-col sm:flex-row items-start justify-between relative z-10">
<div class="mb-4 sm:mb-0">
<div class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800 mb-3 border border-indigo-200">
Departemen: {{ $position->department->name ?? 'Tidak Ada Departemen Induk' }}
</div>
<h1 class="text-3xl font-extrabold text-slate-900">{{ $position->name }}</h1>
</div>
<div class="bg-emerald-100 text-emerald-700 px-5 py-3 rounded-xl text-center">
<span class="block text-2xl font-bold">0</span>
<span class="block text-[10px] uppercase tracking-wider font-bold mt-1 opacity-80">Karyawan</span>
</div>
</div>
</div>
<h3 class="text-lg font-bold text-slate-800 mb-4">Daftar Karyawan dengan Jabatan Ini</h3>
<div class="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
<table class="w-full text-left text-sm">
<thead class="bg-slate-50 text-slate-500">
<tr>
<th class="p-4 font-semibold">Nama Karyawan</th>
<th class="p-4 font-semibold">NIK</th>
<th class="p-4 font-semibold text-right">Status</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
<tr>
<td colspan="3" class="p-8 text-center text-slate-500 italic">
<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="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>
Belum ada karyawan yang terdaftar dengan jabatan ini.
</td>
</tr>
</tbody>
</table>
</div>
</div>
@endsection
@@ -0,0 +1,84 @@
@extends('layouts.app')
@section('content')
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div class="mb-6 flex items-center justify-between">
<div class="flex items-center space-x-3">
<a href="{{ route('admin.reports.training') }}" class="text-slate-400 hover:text-indigo-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
</a>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Rapor Evaluasi Karyawan</h2>
</div>
<button class="px-4 py-2 bg-slate-900 text-white rounded-lg text-sm font-semibold shadow-md hover:bg-slate-800 flex items-center">
<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="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"></path></svg>
Cetak PDF
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-8">
<div class="bg-white p-6 rounded-2xl shadow-sm border border-slate-200">
<p class="text-sm font-semibold text-slate-500 mb-1">Identitas Trainee</p>
<h3 class="text-xl font-extrabold text-slate-900">{{ $user->first_name }} {{ $user->last_name }}</h3>
<p class="text-xs text-slate-400 mt-1">NIK: {{ $user->nik ?? 'N/A' }}</p>
</div>
<div class="bg-indigo-50 p-6 rounded-2xl border border-indigo-100">
<p class="text-sm font-semibold text-indigo-600 mb-1">Total Evaluasi</p>
<h3 class="text-3xl font-extrabold text-indigo-900">{{ $stats['total_exams'] }}</h3>
</div>
<div class="bg-emerald-50 p-6 rounded-2xl border border-emerald-100">
<p class="text-sm font-semibold text-emerald-600 mb-1">Total Lulus</p>
<h3 class="text-3xl font-extrabold text-emerald-900">{{ $stats['passed'] }}</h3>
</div>
<div class="bg-orange-50 p-6 rounded-2xl border border-orange-100">
<p class="text-sm font-semibold text-orange-600 mb-1">Rata-rata Nilai</p>
<h3 class="text-3xl font-extrabold text-orange-900">{{ number_format($stats['avg_score'], 1) }}</h3>
</div>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
<div class="p-6 border-b border-slate-100">
<h3 class="text-lg font-bold text-slate-800">Riwayat Sesi Ujian</h3>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left text-sm whitespace-nowrap">
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wider">
<tr>
<th class="px-6 py-4 font-semibold">Tanggal Ujian</th>
<th class="px-6 py-4 font-semibold">ID / Sesi Ujian</th>
<th class="px-6 py-4 font-semibold text-center">Skor Akhir</th>
<th class="px-6 py-4 font-semibold text-center">Status</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700">
@forelse($examHistory as $history)
<tr class="hover:bg-slate-50 transition-colors">
<td class="px-6 py-4 text-slate-500 font-medium">
{{ $history->created_at->format('d M Y - H:i') }}
</td>
<td class="px-6 py-4 font-bold text-slate-900">
Exam ID: #{{ $history->exam_id }}
</td>
<td class="px-6 py-4 text-center font-extrabold {{ $history->score >= 70 ? 'text-emerald-600' : 'text-red-500' }}">
{{ $history->score }}
</td>
<td class="px-6 py-4 text-center">
@if($history->is_passed)
<span class="px-3 py-1 text-xs font-bold bg-emerald-100 text-emerald-700 rounded-full">LULUS</span>
@else
<span class="px-3 py-1 text-xs font-bold bg-red-100 text-red-700 rounded-full">GAGAL</span>
@endif
</td>
</tr>
@empty
<tr>
<td colspan="4" class="px-6 py-8 text-center text-slate-500">
Karyawan ini belum pernah mengikuti evaluasi ujian.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,67 @@
@extends('layouts.app')
@section('content')
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div class="mb-8">
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Laporan Pelatihan Karyawan</h2>
<p class="text-sm text-slate-500 mt-1">Pantau progres evaluasi CPOB dan kelulusan ujian setiap karyawan secara realtime.</p>
</div>
<div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-left text-sm whitespace-nowrap">
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wider">
<tr>
<th class="px-6 py-4 font-semibold">Nama Karyawan</th>
<th class="px-6 py-4 font-semibold text-center">Total Ujian</th>
<th class="px-6 py-4 font-semibold text-center">Lulus</th>
<th class="px-6 py-4 font-semibold text-center">Rata-rata Nilai</th>
<th class="px-6 py-4 font-semibold text-right">Aksi</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-slate-700">
@forelse($trainees as $trainee)
@php
$totalExams = $trainee->examResults->count();
$passed = $trainee->examResults->where('is_passed', true)->count();
$avgScore = $totalExams > 0 ? $trainee->examResults->avg('score') : 0;
@endphp
<tr class="hover:bg-slate-50 transition-colors">
<td class="px-6 py-4">
<div class="font-bold text-slate-900">{{ $trainee->first_name }} {{ $trainee->last_name }}</div>
<div class="text-xs text-slate-500">{{ $trainee->email }}</div>
</td>
<td class="px-6 py-4 text-center font-medium">{{ $totalExams }}</td>
<td class="px-6 py-4 text-center">
<span class="px-2.5 py-1 text-xs font-bold rounded-full {{ $passed > 0 ? 'bg-emerald-100 text-emerald-700' : 'bg-slate-100 text-slate-500' }}">
{{ $passed }} Modul
</span>
</td>
<td class="px-6 py-4 text-center font-bold {{ $avgScore >= 70 ? 'text-emerald-600' : 'text-red-500' }}">
{{ number_format($avgScore, 1) }}
</td>
<td class="px-6 py-4 text-right">
<a href="{{ route('admin.reports.training.show', $trainee->id) }}" class="inline-flex items-center text-sm font-semibold text-indigo-600 hover:text-indigo-800 transition-colors">
Lihat Detail
<svg class="w-4 h-4 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>
</a>
</td>
</tr>
@empty
<tr>
<td colspan="5" class="px-6 py-12 text-center text-slate-500">
Belum ada data evaluasi karyawan yang dapat ditampilkan.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@if($trainees->hasPages())
<div class="p-4 border-t border-slate-100">
{{ $trainees->links() }}
</div>
@endif
</div>
</div>
@endsection
@@ -0,0 +1,57 @@
@extends('layouts.app')
@section('title', 'Master SOP - HRIS')
@section('content')
<div class="max-w-7xl mx-auto">
<div class="flex justify-between items-center mb-6">
<div>
<h2 class="text-2xl font-bold text-slate-800 tracking-tight">Dokumen SOP & CPOB</h2>
<p class="text-sm text-slate-500">Pusat data prosedur operasi standar perusahaan.</p>
</div>
<a href="{{ route('admin.sops.create') }}" class="px-4 py-2 bg-indigo-600 text-white rounded-md text-sm font-semibold hover:bg-indigo-700 shadow-sm transition-all">
+ Registrasi SOP
</a>
</div>
<div class="bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse">
<thead>
<tr class="bg-slate-50 border-b border-slate-200 text-xs uppercase tracking-wider text-slate-500 font-bold">
<th class="p-4">Kode SOP</th>
<th class="p-4">Judul Dokumen</th>
<th class="p-4">Versi</th>
<th class="p-4">Status</th>
<th class="p-4 text-right">Aksi</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-sm text-slate-700">
@foreach($sops as $sop)
<tr class="hover:bg-slate-50">
<td class="p-4 font-mono font-medium">{{ $sop->sop_code }}</td>
<td class="p-4 font-bold text-slate-800">{{ $sop->title }}</td>
<td class="p-4">v{{ $sop->version }}</td>
<td class="p-4">
@if($sop->status == 'Active')
<span class="px-2.5 py-1 bg-emerald-100 text-emerald-700 text-xs font-bold rounded-full">Active</span>
@elseif($sop->status == 'Draft')
<span class="px-2.5 py-1 bg-amber-100 text-amber-700 text-xs font-bold rounded-full">Draft</span>
@else
<span class="px-2.5 py-1 bg-slate-200 text-slate-700 text-xs font-bold rounded-full">Obsolete</span>
@endif
</td>
<td class="p-4 text-right">
<a href="#" class="text-slate-500 hover:text-indigo-600 font-medium text-xs">Lihat Detail</a>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="p-4 border-t border-slate-100">
{{ $sops->links() }}
</div>
</div>
</div>
@endsection