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,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