kas, spp, penialaian

This commit is contained in:
SitiAfiah 2026-05-03 14:41:36 +07:00
parent 03fa985785
commit f7db432276
25 changed files with 1840 additions and 427 deletions

View File

@ -110,47 +110,54 @@ public function edit($id)
// 5. Update Data Anggota
public function update(Request $request, $id)
{
$anggota = Anggota::findOrFail($id);
$user = User::findOrFail($anggota->user_id);
{
$anggota = Anggota::findOrFail($id);
$user = User::findOrFail($anggota->user_id);
$request->validate([
'email' => 'required|email|unique:users,email,' . $user->id,
'nama_lengkap' => 'required',
'no_hp' => 'required',
'role_id' => 'required|exists:role,id',
'kolat_id' => 'required|exists:kolat,id',
'status' => 'required|in:aktif,Non-Aktif',
$request->validate([
'email' => 'required|email|unique:users,email,' . $user->id,
'nama_lengkap' => 'required|string|max:255',
'no_hp' => 'required',
'role_id' => 'required|exists:role,id',
'kolat_id' => 'required|exists:kolat,id',
'status' => 'required|in:Aktif,Non-Aktif',
]);
DB::beginTransaction();
try {
// 1. Update tabel Users (Email & Role)
$user->update([
'email' => $request->email,
'role_id' => $request->role_id,
]);
DB::beginTransaction();
// 2. Ambil nama jabatan baru dari role_id
$role = Role::find($request->role_id);
$nama_jabatan = strtolower($role->nama_role);
try {
// A. Update tabel User (email & role)
$user->update([
'email' => $request->email,
'role_id' => $request->role_id
]);
// 3. Kelola Upload Foto SK (jika ada)
$data = $request->all();
$data['jabatan'] = $nama_jabatan;
// B. Update jabatan berdasarkan role baru
$role = Role::find($request->role_id);
$nama_jabatan = strtolower($role->nama_role);
// C. Update tabel Anggota
$data_anggota = $request->all();
$data_anggota['jabatan'] = $nama_jabatan;
$anggota->update($data_anggota);
DB::commit();
return redirect()->route('anggota.anggota')
->with('success', 'Data ' . $anggota->nama_lengkap . ' berhasil diperbarui!');
} catch (\Exception $e) {
DB::rollBack();
Log::error("Gagal update anggota: " . $e->getMessage());
return back()->with('error', 'Terjadi kesalahan saat memperbarui data.');
if ($request->hasFile('foto_sk')) {
$file = $request->file('foto_sk');
$nama_file = time() . "_" . $file->getClientOriginalName();
$file->move(public_path('uploads/sk'), $nama_file);
$data['foto_sk'] = $nama_file;
}
// 4. Update tabel Anggota
$anggota->update($data);
DB::commit();
return redirect()->route('anggota.anggota')
->with('success', 'Data ' . $anggota->nama_lengkap . ' berhasil diperbarui!');
} catch (\Exception $e) {
DB::rollBack();
return back()->with('error', 'Gagal update: ' . $e->getMessage());
}
}
}

View File

@ -0,0 +1,120 @@
<?php
namespace App\Http\Controllers;
use App\Models\Kas;
use Illuminate\Http\Request;
use Carbon\Carbon;
class KasController extends Controller
{
public function index(Request $request)
{
// Menggunakan scope query untuk filter
$query = Kas::query();
if ($request->filled('jenis')) {
$query->where('jenis', $request->jenis);
}
if ($request->filled('dari') && $request->filled('sampai')) {
$query->whereBetween('tanggal', [$request->dari, $request->sampai]);
}
$data_kas = $query->orderBy('tanggal', 'asc')->orderBy('id', 'asc')->get();
// Statistik tetap menggunakan data keseluruhan
$saldo_sekarang = Kas::saldoTerakhir();
$pemasukan_bulan_ini = Kas::where('jenis', 'masuk')
->whereMonth('tanggal', now()->month)
->whereYear('tanggal', now()->year)
->sum('nominal');
$pengeluaran_bulan_ini = Kas::where('jenis', 'keluar')
->whereMonth('tanggal', now()->month)
->whereYear('tanggal', now()->year)
->sum('nominal');
return view('kas.index', compact('data_kas', 'saldo_sekarang', 'pemasukan_bulan_ini', 'pengeluaran_bulan_ini'));
}
/**
* Fungsi untuk menyimpan data transaksi baru
*/
public function store(Request $request)
{
// 1. Validasi input
$request->validate([
'tanggal' => 'required|date',
'jenis' => 'required|in:masuk,keluar',
'kategori' => 'required|string',
'nominal' => 'required|numeric|min:0',
]);
// 2. Ambil saldo terakhir untuk kalkulasi saldo_akhir
$saldo_terakhir = Kas::saldoTerakhir();
// 3. Hitung saldo baru
if ($request->jenis == 'masuk') {
$saldo_baru = $saldo_terakhir + $request->nominal;
} else {
$saldo_baru = $saldo_terakhir - $request->nominal;
}
// 4. Simpan ke database
Kas::create([
'tanggal' => $request->tanggal,
'jenis' => $request->jenis,
'kategori' => $request->kategori,
'nominal' => $request->nominal,
'keterangan' => $request->keterangan,
'saldo_akhir' => $saldo_baru,
]);
return redirect()->route('kas.index')->with('success', 'Transaksi berhasil ditambahkan!');
}
public function destroy($id)
{
$kas = Kas::findOrFail($id);
$kas->delete();
return redirect()->back()->with('success', 'Transaksi berhasil dihapus!');
}
public function update(Request $request, $id)
{
$request->validate([
'tanggal' => 'required|date',
'jenis' => 'required|in:masuk,keluar',
'kategori' => 'required|string',
'nominal' => 'required|numeric',
]);
$kas = Kas::findOrFail($id);
// Logika perhitungan ulang saldo:
// Kita ambil saldo sebelum transaksi ini terjadi
$saldo_sebelumnya = Kas::where('id', '<', $kas->id)->orderBy('id', 'desc')->first()->saldo_akhir ?? 0;
// Hitung saldo akhir baru untuk baris ini
$saldo_akhir_baru = ($request->jenis == 'masuk')
? $saldo_sebelumnya + $request->nominal
: $saldo_sebelumnya - $request->nominal;
$kas->update([
'tanggal' => $request->tanggal,
'jenis' => $request->jenis,
'kategori' => $request->kategori,
'nominal' => $request->nominal,
'keterangan' => $request->keterangan,
'saldo_akhir' => $saldo_akhir_baru
]);
// Catatan: Idealnya setelah edit, semua baris setelahnya juga diupdate saldonya.
// Tapi untuk tahap awal, ini sudah cukup fungsional.
return redirect()->back()->with('success', 'Transaksi berhasil diperbarui!');
}
}

View File

@ -2,9 +2,112 @@
namespace App\Http\Controllers;
use App\Models\Anggota;
use App\Models\Penilaian;
use Carbon\Carbon;
use Illuminate\Http\Request;
class PenilaianController extends Controller
{
//
public function index()
{
$data_pelatih = Anggota::where('jabatan', 'Pelatih')
->with('kolat')
->get();
return view('penilaian.index', compact('data_pelatih'));
}
public function create($id)
{
// BYPASS: Hapus pengecekan auth() agar tidak mental ke login
$pelatih = Anggota::with('kolat')->findOrFail($id);
return view('penilaian.create', compact('pelatih'));
}
public function store(Request $request)
{
$request->validate([
'pelatih_id' => 'required',
'metode_pelatihan' => 'required|integer|min:1|max:5',
'komunikasi' => 'required|integer|min:1|max:5',
'sikap_kepribadian' => 'required|integer|min:1|max:5',
'kepemimpinan' => 'required|integer|min:1|max:5',
'konsistensi_komitmen' => 'required|integer|min:1|max:5',
'kedekatan_interpersonal' => 'required|integer|min:1|max:5',
'kritik_saran' => 'nullable|string'
]);
Penilaian::create([
'pelatih_id' => $request->pelatih_id,
'anggota_id' => 1, // TESTING: Isi manual ID Anggota penilai (misal ID 1)
'bulan_evaluasi' => Carbon::now()->startOfMonth(),
'metode_pelatihan' => $request->metode_pelatihan,
'komunikasi' => $request->komunikasi,
'sikap_kepribadian' => $request->sikap_kepribadian,
'kepemimpinan' => $request->kepemimpinan,
'konsistensi_komitmen' => $request->konsistensi_komitmen,
'kedekatan_interpersonal' => $request->kedekatan_interpersonal,
'kritik_saran' => $request->kritik_saran,
]);
return redirect()->route('penilaian.index')->with('success', 'Penilaian berhasil disimpan!');
}
public function show($id)
{
$pelatih = Anggota::with('kolat')->findOrFail($id);
// Hitung rata-rata tiap kriteria bulan ini
$rekap = Penilaian::where('pelatih_id', $id)
->whereMonth('bulan_evaluasi', now()->month)
->selectRaw('
AVG(metode_pelatihan) as avg_metode,
AVG(komunikasi) as avg_komunikasi,
AVG(sikap_kepribadian) as avg_sikap,
AVG(kepemimpinan) as avg_kepemimpinan,
AVG(konsistensi_komitmen) as avg_komitmen,
AVG(kedekatan_interpersonal) as avg_interpersonal
')->first();
// Ambil ulasan/kritik saran (Pluck agar anonim)
$ulasan = Penilaian::where('pelatih_id', $id)
->whereMonth('bulan_evaluasi', now()->month)
->whereNotNull('kritik_saran')
->pluck('kritik_saran');
return view('penilaian.rekap', compact('pelatih', 'rekap', 'ulasan'));
}
public function exportPdf($id)
{
// 1. Ambil data pelatih
$pelatih = Anggota::with('kolat')->findOrFail($id);
// 2. Hitung rata-rata nilai (Rekap)
$rekap = Penilaian::where('pelatih_id', $id)
->whereMonth('bulan_evaluasi', now()->month)
->selectRaw('
AVG(metode_pelatihan) as avg_metode,
AVG(komunikasi) as avg_komunikasi,
AVG(sikap_kepribadian) as avg_sikap,
AVG(kepemimpinan) as avg_kepemimpinan,
AVG(konsistensi_komitmen) as avg_komitmen,
AVG(kedekatan_interpersonal) as avg_interpersonal
')->first();
// 3. Ambil ulasan ulasan anggota
$ulasan = Penilaian::where('pelatih_id', $id)
->whereMonth('bulan_evaluasi', now()->month)
->whereNotNull('kritik_saran')
->pluck('kritik_saran');
// 4. Panggil file view "laporan_pdf" sesuai nama filemu
$pdf = Pdf::loadView('penilaian.laporan_pdf', compact('pelatih', 'rekap', 'ulasan'));
// 5. Download file PDF
return $pdf->download('Laporan-Performa-' . $pelatih->nama_lengkap . '.pdf');
}
}

View File

@ -0,0 +1,156 @@
<?php
namespace App\Http\Controllers;
use App\Models\Anggota;
use App\Models\Kas;
use App\Models\Spp;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
class SppController extends Controller
{
public function index(Request $request)
{
$query = Spp::with(['anggota', 'kolat']);
// Filter
if ($request->filled('status')) {
$query->where('status', $request->status);
}
if ($request->filled('bulan')) {
$query->where('bulan', $request->bulan);
}
if ($request->filled('tahun')) {
$query->where('tahun', $request->tahun);
}
if ($request->filled('cari')) {
$query->whereHas('anggota', function($q) use ($request) {
$q->where('nama', 'like', '%' . $request->cari . '%');
});
}
$data_spp = $query->orderBy('tahun', 'desc')
->orderBy('bulan', 'desc')
->get();
$stats = [
'lunas' => Spp::where('status', 'lunas')->count(),
'pending' => Spp::where('status', 'pending')->count(),
'belum_bayar' => Spp::where('status', 'belum_bayar')->count(),
'total_pemasukan' => Spp::where('status', 'lunas')->sum('nominal')
];
return view('spp.pengurus.index', compact('data_spp', 'stats'));
}
public function create()
{
// Pastikan nama kolom di database adalah 'nama', bukan 'nama_lengkap' (sesuai diskusi sebelumnya)
$data_anggota = Anggota::orderBy('nama_lengkap', 'asc')->get();
return view('spp.pengurus.create', compact('data_anggota'));
}
public function store(Request $request)
{
$request->validate([
'anggota_id' => 'required|exists:anggotas,id',
'bulan' => 'required',
'tahun' => 'required',
'nominal' => 'required|numeric',
'jatuh_tempo' => 'required|date',
]);
try {
$anggota = Anggota::findOrFail($request->anggota_id);
Spp::create([
'anggota_id' => $request->anggota_id,
'kolat_id' => $anggota->kolat_id,
'bulan' => $request->bulan,
'tahun' => $request->tahun,
'nominal' => $request->nominal,
'jatuh_tempo' => $request->jatuh_tempo,
'status' => 'belum_bayar',
]);
return redirect()->route('spp.index')->with('success', 'Tagihan berhasil dibuat!');
} catch (\Exception $e) {
return redirect()->back()->withInput()->with('error', 'Gagal menyimpan: ' . $e->getMessage());
}
}
public function bayar(Request $request, $id)
{
// Perbaikan: Pakai 'anggota' (singular) sesuai relasi model biasanya
$spp = Spp::with('anggota')->findOrFail($id);
if ($spp->status == 'lunas') {
return redirect()->back()->with('error', 'Tagihan ini sudah lunas.');
}
DB::beginTransaction();
try {
$saldo_terakhir = Kas::saldoTerakhir() ?? 0;
$saldo_baru = $saldo_terakhir + $spp->nominal;
$kas = Kas::create([
'tanggal' => now(),
'jenis' => 'masuk',
'kategori' => 'SPP',
'nominal' => $spp->nominal,
'keterangan' => "Bayar SPP " . $spp->anggota->nama . " - " . $spp->bulan . " " . $spp->tahun,
'saldo_akhir' => $saldo_baru
]);
$spp->update([
'status' => 'lunas',
'tanggal_bayar' => now(),
'kas_id' => $kas->id
]);
DB::commit();
return redirect()->back()->with('success', 'Pembayaran SPP berhasil dicatat!');
} catch (\Exception $e) {
DB::rollback();
return redirect()->back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
}
}
public function generateTagihan(Request $request)
{
$bulanIni = Carbon::now()->translatedFormat('F');
$tahunIni = Carbon::now()->year;
$jatuhTempo = Carbon::now()->day(10);
$anggota = Anggota::all();
DB::beginTransaction();
try {
foreach ($anggota as $agt) {
$exists = Spp::where('anggota_id', $agt->id)
->where('bulan', $bulanIni)
->where('tahun', $tahunIni)
->exists();
if (!$exists) {
Spp::create([
'anggota_id' => $agt->id,
'kolat_id' => $agt->kolat_id,
'bulan' => $bulanIni,
'tahun' => $tahunIni,
'nominal' => 50000,
'jatuh_tempo' => $jatuhTempo,
'status' => 'belum_bayar',
]);
}
}
DB::commit();
return redirect()->route('spp.index')->with('success', "Tagihan berhasil dibuat!");
} catch (\Exception $e) {
DB::rollback();
return redirect()->back()->with('error', 'Gagal: ' . $e->getMessage());
}
}
}

View File

@ -54,4 +54,5 @@ public function user()
return $this->belongsTo(User::class, 'user_id');
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Kas extends Model
{
use HasFactory;
protected $table = 'kas';
protected $fillable = [
'tanggal',
'jenis',
'kategori',
'nominal',
'keterangan',
'saldo_akhir'
];
/**
* Scope untuk mendapatkan saldo terakhir.
* Ini akan memudahkan kamu saat ingin menghitung saldo baru.
*/
public static function saldoTerakhir()
{
$last = self::orderBy('id', 'desc')->first();
return $last ? $last->saldo_akhir : 0;
}
}

View File

@ -8,16 +8,18 @@
class Penilaian extends Model
{
use HasFactory;
protected $fillable = [
'pelatih_id',
'anggota_id',
'bulan_evaluasi',
'kedisiplinan',
'kejelasan_materi',
'penguasaan_teknik',
'sikap_perilaku',
'kritik_saran'
];
protected $fillable = [
'pelatih_id',
'anggota_id',
'bulan_evaluasi',
'metode_pelatihan',
'komunikasi',
'sikap_kepribadian',
'kepemimpinan',
'konsistensi_komitmen',
'kedekatan_interpersonal',
'kritik_saran'
];
// Relasi: Siapa pelatih yang sedang dinilai?
public function pelatih()
@ -30,4 +32,29 @@ public function penilai()
{
return $this->belongsTo(Anggota::class, 'anggota_id');
}
public function show($id)
{
$pelatih = Anggota::with('kolat')->findOrFail($id);
// Hitung rata-rata tiap kriteria bulan ini
$rekap = Penilaian::where('pelatih_id', $id)
->whereMonth('bulan_evaluasi', now()->month)
->selectRaw('
AVG(metode_pelatihan) as avg_metode,
AVG(komunikasi) as avg_komunikasi,
AVG(sikap_kepribadian) as avg_sikap,
AVG(kepemimpinan) as avg_kepemimpinan,
AVG(konsistensi_komitmen) as avg_komitmen,
AVG(kedekatan_interpersonal) as avg_interpersonal
')->first();
// Ambil ulasan/kritik saran (Pluck agar anonim)
$ulasan = Penilaian::where('pelatih_id', $id)
->whereMonth('bulan_evaluasi', now()->month)
->whereNotNull('kritik_saran')
->pluck('kritik_saran');
return view('penilaian.rekap', compact('pelatih', 'rekap', 'ulasan'));
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Spp extends Model
{
protected $table = 'spp';
protected $fillable = [
'anggota_id',
'kolat_id',
'kas_id',
'bulan',
'tahun',
'nominal',
'status',
'jatuh_tempo',
'keterangan'
];
// Relasi ke Anggota
public function anggota()
{
return $this->belongsTo(Anggota::class);
}
// Relasi ke Kolat
public function kolat()
{
return $this->belongsTo(Kolat::class);
}
// Relasi ke Kas
public function kas()
{
return $this->belongsTo(Kas::class);
}
}

View File

@ -13,7 +13,6 @@ public function up(): void
{
Schema::create('anggotas', function (Blueprint $table) {
$table->id();
// --- RELASI (Penghubung ke Dropdown) ---
$table->foreignId('role_id')->constrained('role')->onDelete('cascade');
$table->foreignId('kolat_id')->constrained('kolat')->onDelete('cascade');

View File

@ -13,16 +13,19 @@ public function up(): void
{
Schema::create('penilaians', function (Blueprint $table) {
$table->id();
$table->foreignId('pelatih_id')->constrained('anggotas')->onDelete('cascade'); // Pelatih yang dinilai
$table->foreignId('anggota_id')->constrained('anggotas')->onDelete('cascade'); // Anggota yang menilai
$table->date('bulan_evaluasi'); // Untuk menandai evaluasi bulan apa
$table->foreignId('pelatih_id')->constrained('anggotas')->onDelete('cascade');
$table->foreignId('anggota_id')->constrained('anggotas')->onDelete('cascade');
$table->date('bulan_evaluasi');
// Kriteria Evaluasi Pelatih (Skala 1-5 atau 1-10)
$table->integer('kedisiplinan')->default(0);
$table->integer('kejelasan_materi')->default(0);
$table->integer('penguasaan_teknik')->default(0);
$table->integer('sikap_perilaku')->default(0); // Etika pelatih
$table->text('kritik_saran')->nullable(); // Masukan dari anggota
// 6 Kriteria Evaluasi Hasil Wawancara (Skala 1-5)
$table->integer('metode_pelatihan')->default(0);
$table->integer('komunikasi')->default(0);
$table->integer('sikap_kepribadian')->default(0);
$table->integer('kepemimpinan')->default(0);
$table->integer('konsistensi_komitmen')->default(0);
$table->integer('kedekatan_interpersonal')->default(0);
$table->text('kritik_saran')->nullable();
$table->timestamps();
});
}

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('kas', function (Blueprint $table) {
$table->id();
$table->date('tanggal');
$table->enum('jenis', ['masuk', 'keluar']);
// Kategori untuk membedakan asal uang (SPP, Seragam, Operasional, dll)
$table->string('kategori');
$table->decimal('nominal', 15, 2);
$table->text('keterangan')->nullable();
// Saldo akhir disimpan per baris transaksi agar history saldo terlihat jelas
$table->decimal('saldo_akhir', 15, 2)->default(0);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('kas');
}
};

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('spp', function (Blueprint $table) {
$table->id();
// Gunakan nama tabel sesuai yang ada di Schema::create tabel tujuan
$table->foreignId('anggota_id')->constrained('anggotas')->onDelete('cascade');
$table->foreignId('kolat_id')->constrained('kolat')->onDelete('cascade');
$table->foreignId('kas_id')->nullable()->constrained('kas')->onDelete('set null');
$table->string('bulan');
$table->year('tahun');
$table->date('jatuh_tempo');
$table->integer('nominal');
$table->enum('status', ['lunas', 'pending', 'belum_bayar']);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('spp');
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -62,7 +62,7 @@
<div class="col-md-6">
<label class="form-label fw-bold">No. WhatsApp</label>
<div class="input-group">
<span class="input-group-text bg-light border-end-0">+62</span>
<input type="number" name="no_hp" class="form-control" value="{{ old('no_hp', $anggota->no_hp ?? '') }}" placeholder="81234567xxx" required>
</div>
</div>

View File

@ -2,10 +2,6 @@
@section('content')
<div class="container-fluid py-4">
<<<<<<< Updated upstream
<!-- Header & Breadcrumb -->
=======
>>>>>>> Stashed changes
<div class="page-header mb-4 text-start">
<nav aria-label="breadcrumb">
<ol class="breadcrumb bg-transparent p-0 mb-2">
@ -20,183 +16,43 @@ class="text-muted text-decoration-none small">Daftar Anggota</a></li>
<div class="row">
<div class="col-md-12">
<<<<<<< Updated upstream
<!-- Form Start - Pastikan enctype ada untuk upload foto SK -->
=======
>>>>>>> Stashed changes
<form action="{{ route('anggota.update', $anggota->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<<<<<<< Updated upstream
<!-- CARD 1: INFORMASI PRIBADI -->
<div class="card border-0 shadow-sm mb-4" style="border-radius: 20px;">
<div class="card-header bg-white border-0 pt-4 px-4">
<h5 class="fw-bold text-primary mb-0"><i class="icon-user me-2"></i>Informasi Pribadi</h5>
<h5 class="fw-bold text-primary mb-0"><i class="icon-user me-2"></i>Informasi Akun & Pribadi</h5>
</div>
<div class="card-body p-4">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-bold">No Induk</label>
<input type="text" name="no_induk" class="form-control bg-light fw-bold text-primary"
value="{{ $anggota->no_induk }}" readonly>
<small class="text-muted" style="font-size: 11px;">* No. induk permanen dan tidak dapat
diubah</small>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Nama Lengkap</label>
<input type="text" name="nama_lengkap" class="form-control bg-light"
value="{{ $anggota->nama_lengkap }}" required>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">No. WhatsApp (HP)</label>
<div class="input-group">
<span class="input-group-text bg-light border-end-0">+62</span>
<input type="number" name="no_hp" class="form-control"
value="{{ $anggota->no_hp }}" placeholder="81234567xxx" required>
</div>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Alamat Lengkap</label>
<input type="text" name="alamat" class="form-control" value="{{ $anggota->alamat }}"
required>
</div>
</div>
</div>
</div>
<!-- CARD 2: INFORMASI ORGANISASI -->
<div class="card border-0 shadow-sm mb-4" style="border-radius: 20px;">
<div class="card-header bg-white border-0 pt-4 px-4">
<h5 class="fw-bold text-success mb-0"><i class="icon-badge me-2"></i>Informasi Organisasi</h5>
</div>
<div class="card-body p-4">
<div class="row g-3">
<div class="col-md-4">
<label class="form-label fw-bold">Jabatan Organisasi</label>
<select name="jabatan" id="jabatanSelect" class="form-select border-primary"
onchange="toggleSKFields()" required>
<option value="anggota" {{ $anggota->jabatan == 'anggota' ? 'selected' : '' }}>
Anggota</option>
<option value="pelatih" {{ $anggota->jabatan == 'pelatih' ? 'selected' : '' }}>
Pelatih</option>
<option value="pengurus" {{ $anggota->jabatan == 'pengurus' ? 'selected' : '' }}>
Pengurus</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Tingkatan</label>
<input type="text" name="tingkatan" class="form-control"
value="{{ $anggota->tingkatan }}" required>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Status Anggota</label>
<select name="status" class="form-select" required>
<option value="Aktif" {{ $anggota->status == 'Aktif' ? 'selected' : '' }}>Aktif
</option>
<option value="Non-Aktif" {{ $anggota->status == 'Non-Aktif' ? 'selected' : '' }}>
Non-Aktif</option>
</select>
</div>
<!-- BOX DATA SK (Otomatis muncul jika pilih Pelatih/Pengurus) -->
<div id="boxSK"
class="col-12 mt-3 p-4 bg-light rounded-4 border border-dashed border-danger"
style="display: none;">
<h6 class="text-danger fw-bold mb-3"><i class="icon-certificate me-2"></i>Data Legalitas
SK (Wajib diisi untuk Pelatih/Pengurus)</h6>
<div class="row g-3">
<div class="col-md-3">
<label class="form-label small fw-bold">Nomor SK</label>
<input type="text" name="no_sk" class="form-control"
value="{{ $anggota->no_sk ?? '' }}" placeholder="Contoh: SK/001/2026">
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Tanggal SK</label>
<input type="date" name="tgl_sk" class="form-control"
value="{{ $anggota->tgl_sk ?? '' }}">
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Masa Berlaku</label>
<input type="date" name="masa_berlaku" class="form-control"
value="{{ $anggota->masa_berlaku ?? '' }}">
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Upload Scan SK</label>
<input type="file" name="foto_sk" class="form-control">
@if ($anggota->foto_sk)
<small class="text-muted mt-1 d-block">File:
{{ $anggota->foto_sk }}</small>
@endif
</div>
</div>
</div>
{{-- <div class="col-md-12 mt-3">
<label class="form-label fw-bold">Asal Kolat</label>
<input type="text" name="asal_kolat" class="form-control" value="{{ $anggota->asal_kolat }}" required>
</div> --}}
<div class="col-md-12 mt-3">
<label class="form-label fw-bold">Asal Kolat</label>
<select name="kolat_id" class="form-select" required>
<option value="" disabled>-- Pilih Kolat --</option>
@foreach ($data_kolat as $kolat)
<option value="{{ $kolat->id }}"
{{ $anggota->kolat_id == $kolat->id ? 'selected' : '' }}>
{{ $kolat->nama_kolat }}
</option>
@endforeach
</select>
</div>
</div>
</div>
<!-- FOOTER CARD UNTUK BUTTON -->
<div class="card-footer bg-light border-0 p-4" style="border-radius: 0 0 20px 20px;">
<div class="d-flex justify-content-end align-items-center gap-3">
<a href="{{ route('anggota.anggota') }}"
class="btn btn-outline-secondary px-4 fw-bold btn-cancel">
<i class="icon-x me-1"></i> Batal
</a>
<button type="submit" class="btn btn-primary px-5 fw-bold btn-save shadow">
<i class="icon-check me-1"></i> Simpan Perubahan
</button>
</div>
</div>
</div>
=======
<div class="card border-0 shadow-sm mb-4" style="border-radius: 20px;">
<div class="card-header bg-white border-0 pt-4 px-4">
<h5 class="fw-bold text-primary mb-0"><i class="icon-user me-2"></i>Informasi Pribadi & Akun</h5>
</div>
<div class="card-body p-4">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-bold">No Induk</label>
<input type="text" class="form-control bg-light fw-bold text-primary"
value="{{ $anggota->no_induk }}" readonly>
<small class="text-muted" style="font-size: 11px;">* No. induk permanen</small>
<label class="form-label fw-bold">Alamat Email (Login)</label>
<input type="email" name="email" class="form-control"
value="{{ old('email', $anggota->user->email ?? '') }}" required>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Nama Lengkap</label>
<input type="text" name="nama_lengkap" class="form-control"
value="{{ old('nama_lengkap', $anggota->nama_lengkap) }}" required>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Alamat Email (Login)</label>
<input type="email" name="email" class="form-control"
value="{{ old('email', $anggota->user->email ?? '') }}" required>
<small class="text-muted" style="font-size: 11px;">* Email digunakan untuk masuk ke sistem</small>
<div class="col-md-4">
<label class="form-label fw-bold">No Induk</label>
<input type="text" class="form-control bg-light fw-bold text-primary"
value="{{ $anggota->no_induk }}" readonly>
<small class="text-muted" style="font-size: 11px;">* No. induk permanen</small>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">No. WhatsApp (HP)</label>
<div class="input-group">
<span class="input-group-text bg-light border-end-0">+62</span>
<input type="number" name="no_hp" class="form-control"
value="{{ old('no_hp', $anggota->no_hp) }}" placeholder="81234567xxx" required>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">No. WhatsApp</label>
<input type="number" name="no_hp" class="form-control"
value="{{ old('no_hp', $anggota->no_hp) }}" required>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Jenis Kelamin</label>
<select name="jenis_kelamin" class="form-select" required>
<option value="L" {{ $anggota->jenis_kelamin == 'L' ? 'selected' : '' }}>Laki-laki</option>
<option value="P" {{ $anggota->jenis_kelamin == 'P' ? 'selected' : '' }}>Perempuan</option>
</select>
</div>
<div class="col-md-12">
<label class="form-label fw-bold">Alamat Lengkap</label>
@ -214,51 +70,40 @@ class="btn btn-outline-secondary px-4 fw-bold btn-cancel">
<div class="row g-3">
<div class="col-md-4">
<label class="form-label fw-bold">Jabatan / Role</label>
<select name="role_id" id="roleSelect" class="form-select border-primary"
onchange="toggleSKFields()" required>
<option value="" disabled>-- Pilih Jabatan --</option>
@foreach ($data_role as $role)
<option value="{{ $role->id }}"
{{ old('role_id', $anggota->role_id) == $role->id ? 'selected' : '' }}>
<select name="role_id" id="roleSelect" class="form-select border-primary" onchange="toggleSKFields()" required>
@foreach($data_role as $role)
<option value="{{ $role->id }}" {{ $anggota->role_id == $role->id ? 'selected' : '' }}>
{{ $role->nama_role }}
</option>
@endforeach
</select>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Tingkatan Sabuk</label>
<input type="text" name="tingkatan" class="form-control"
value="{{ old('tingkatan', $anggota->tingkatan) }}" required>
<label class="form-label fw-bold">Tingkatan</label>
<input type="text" name="tingkatan" class="form-control" value="{{ $anggota->tingkatan }}" required>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Status Anggota</label>
<select name="status" class="form-select" required>
<option value="aktif" {{ old('status', $anggota->status) == 'aktif' ? 'selected' : '' }}>Aktif</option>
<option value="Non-Aktif" {{ old('status', $anggota->status) == 'Non-Aktif' ? 'selected' : '' }}>Non-Aktif</option>
<option value="Aktif" {{ $anggota->status == 'Aktif' ? 'selected' : '' }}>Aktif</option>
<option value="Non-Aktif" {{ $anggota->status == 'Non-Aktif' ? 'selected' : '' }}>Non-Aktif</option>
</select>
</div>
<div id="boxSK"
class="col-12 mt-3 p-4 bg-light rounded-4 border border-dashed border-danger"
style="display: none;">
<h6 class="text-danger fw-bold mb-3"><i class="icon-certificate me-2"></i>Data Legalitas SK</h6>
<div id="boxSK" class="col-12 mt-3 p-4 bg-light rounded-4 border border-dashed border-danger" style="display: none;">
<h6 class="text-danger fw-bold mb-3"><i class="icon-certificate me-2"></i>Legalitas SK</h6>
<div class="row g-3">
<div class="col-md-4">
<label class="form-label small fw-bold">Nomor SK</label>
<input type="text" name="no_sk" class="form-control"
value="{{ old('no_sk', $anggota->no_sk) }}" placeholder="Contoh: SK/001/2026">
<input type="text" name="no_sk" class="form-control" value="{{ $anggota->no_sk }}">
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Masa Berlaku SK</label>
<input type="date" name="masa_berlaku" class="form-control"
value="{{ old('masa_berlaku', $anggota->masa_berlaku) }}">
<label class="form-label small fw-bold">Masa Berlaku</label>
<input type="date" name="masa_berlaku" class="form-control" value="{{ $anggota->masa_berlaku }}">
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Update File SK (Opsional)</label>
<label class="form-label small fw-bold">Update Foto SK</label>
<input type="file" name="foto_sk" class="form-control">
@if ($anggota->foto_sk)
<small class="text-primary mt-1 d-block"><i class="icon-eye"></i> File saat ini: {{ $anggota->foto_sk }}</small>
@endif
</div>
</div>
</div>
@ -266,10 +111,8 @@ class="col-12 mt-3 p-4 bg-light rounded-4 border border-dashed border-danger"
<div class="col-md-12 mt-3">
<label class="form-label fw-bold">Asal Kolat</label>
<select name="kolat_id" class="form-select" required>
<option value="" disabled>-- Pilih Kolat --</option>
@foreach ($data_kolat as $kolat)
<option value="{{ $kolat->id }}"
{{ old('kolat_id', $anggota->kolat_id) == $kolat->id ? 'selected' : '' }}>
<option value="{{ $kolat->id }}" {{ $anggota->kolat_id == $kolat->id ? 'selected' : '' }}>
{{ $kolat->nama_kolat }}
</option>
@endforeach
@ -279,117 +122,29 @@ class="col-12 mt-3 p-4 bg-light rounded-4 border border-dashed border-danger"
</div>
<div class="card-footer bg-light border-0 p-4" style="border-radius: 0 0 20px 20px;">
<div class="d-flex justify-content-end align-items-center gap-3">
<a href="{{ route('anggota.anggota') }}"
class="btn btn-outline-secondary px-4 fw-bold btn-cancel">
<i class="icon-x me-1"></i> Batal
</a>
<button type="submit" class="btn btn-primary px-5 fw-bold btn-save shadow">
<i class="icon-check me-1"></i> Simpan Perubahan
</button>
<div class="d-flex justify-content-end gap-3">
<a href="{{ route('anggota.anggota') }}" class="btn btn-outline-secondary px-4 fw-bold btn-cancel">Batal</a>
<button type="submit" class="btn btn-primary px-5 fw-bold btn-save shadow">Simpan Perubahan</button>
</div>
</div>
</div>
>>>>>>> Stashed changes
</form>
</div>
</div>
</div>
<<<<<<< Updated upstream
<!-- JAVASCRIPT TOGGLE -->
<script>
function toggleSKFields() {
const jabatan = document.getElementById('jabatanSelect').value;
const roleSelect = document.getElementById('roleSelect');
const selectedText = roleSelect.options[roleSelect.selectedIndex].text.toLowerCase();
const boxSK = document.getElementById('boxSK');
if (jabatan === 'pelatih' || jabatan === 'pengurus') {
if (selectedText.includes('pelatih') || selectedText.includes('pengurus')) {
boxSK.style.display = 'block';
} else {
boxSK.style.display = 'none';
}
}
// Jalankan saat pertama kali halaman dimuat
=======
<script>
function toggleSKFields() {
const roleSelect = document.getElementById('roleSelect');
const boxSK = document.getElementById('boxSK');
if (roleSelect.selectedIndex >= 0) {
const selectedText = roleSelect.options[roleSelect.selectedIndex].text.toLowerCase();
if (selectedText.includes('pelatih') || selectedText.includes('pengurus')) {
boxSK.style.display = 'block';
} else {
boxSK.style.display = 'none';
}
}
}
>>>>>>> Stashed changes
document.addEventListener("DOMContentLoaded", function() {
toggleSKFields();
});
document.addEventListener("DOMContentLoaded", toggleSKFields);
</script>
<style>
<<<<<<< Updated upstream
.form-control,
.form-select {
border-radius: 10px;
padding: 10px 15px;
}
.form-control:focus,
.form-select:focus {
=======
.form-control, .form-select {
border-radius: 10px;
padding: 10px 15px;
border: 1px solid #dce1e7;
}
.form-control:focus, .form-select:focus {
>>>>>>> Stashed changes
border-color: #0d6efd;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.1);
}
.btn-cancel {
border-radius: 12px;
<<<<<<< Updated upstream
transition: all 0.3s ease;
border: 2px solid #6c757d;
}
.btn-cancel:hover {
background-color: #6c757d;
color: white;
transform: translateY(-2px);
}
.btn-save {
border-radius: 12px;
background: (45deg, #0d6efd);
border: none;
transition: all 0.3s ease;
}
.btn-save:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(13, 110, 253, 0.4) !important;
=======
border: 2px solid #6c757d;
}
.btn-save {
border-radius: 12px;
background: linear-gradient(45deg, #0d6efd, #004dc0);
border: none;
color: white;
>>>>>>> Stashed changes
}
</style>
@endsection

View File

@ -0,0 +1,339 @@
@extends('layout.app')
@section('content')
<div class="container-fluid py-4">
<!-- Header Section -->
<div class="page-header mb-4 text-start">
<nav aria-label="breadcrumb">
<ol class="breadcrumb bg-transparent p-0 mb-2">
<li class="breadcrumb-item"><a href="#" class="text-muted text-decoration-none small">Home</a></li>
<li class="breadcrumb-item active text-primary fw-bold small" aria-current="page">Kas Cabang</li>
</ol>
</nav>
<div class="text-start">
<h3 class="fw-bold text-dark mb-1">Buku Kas Digital</h3>
<p class="text-muted small">Pantau arus kas masuk dan keluar secara real-time.</p>
</div>
</div>
@if(session('success'))
<div class="alert alert-success alert-dismissible fade show border-0 shadow-sm mb-4" role="alert" style="border-radius: 15px;">
<i class="bi bi-check-circle-fill me-2"></i> <strong>Berhasil!</strong> {{ session('success') }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
<!-- Row Statistik Utama -->
<div class="row mb-4 g-3 text-start">
<div class="col-md-4">
<div class="card border-0 shadow-sm text-white h-100 overflow-hidden"
style="border-radius: 20px; background: linear-gradient(45deg, #0d6efd, #00c6ff);">
<div class="card-body p-4 position-relative">
<p class="mb-1 small opacity-75">Saldo Kas Saat Ini</p>
<h2 class="fw-bold mb-0 text-nowrap">Rp {{ number_format((float)$saldo_sekarang, 0, ',', '.') }}</h2>
<i class="icon-wallet position-absolute opacity-25" style="font-size: 80px; right: -10px; bottom: -10px;"></i>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-0 shadow-sm h-100 border-start border-success border-4" style="border-radius: 15px;">
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="bg-success-soft rounded-3 p-3 me-3">
<i class="icon-login text-success fs-4"></i>
</div>
<div>
<p class="mb-0 text-muted small fw-bold uppercase">Pemasukan (Bulan Ini)</p>
<h4 class="fw-bold text-success mb-0">Rp {{ number_format((float)$pemasukan_bulan_ini, 0, ',', '.') }}</h4>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-0 shadow-sm h-100 border-start border-danger border-4" style="border-radius: 15px;">
<div class="card-body p-4 text-start">
<div class="d-flex align-items-center">
<div class="bg-danger-soft rounded-3 p-3 me-3 text-start">
<i class="icon-logout text-danger fs-4"></i>
</div>
<div>
<p class="mb-0 text-muted small fw-bold uppercase text-start">Pengeluaran (Bulan Ini)</p>
<h4 class="fw-bold text-danger mb-0 text-start">Rp {{ number_format((float)$pengeluaran_bulan_ini, 0, ',', '.') }}</h4>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Section Tabel -->
<div class="row">
<div class="col-12">
<div class="card border-0 shadow-sm p-2" style="border-radius: 20px;">
<div class="card-body p-4">
<!-- Header Tabel -->
<div class="d-flex justify-content-between align-items-center mb-4 text-start">
<div class="text-start">
<h5 class="card-title mb-0 fw-bold text-dark">Buku Kas Utama</h5>
<p class="text-muted small mb-0">Cabang Jember - Histori seluruh arus kas.</p>
</div>
<div class="d-flex gap-2">
<!-- DROPDOWN FILTER -->
<div class="dropdown">
<button class="btn btn-light border px-4 py-2 dropdown-toggle shadow-sm"
type="button" id="filterDropdown" data-bs-toggle="dropdown"
aria-expanded="false" style="border-radius: 12px;">
<i class="icon-filter me-1"></i> Filter Data
</button>
<div class="dropdown-menu dropdown-menu-end p-4 shadow-lg border-0"
aria-labelledby="filterDropdown" style="width: 300px; border-radius: 20px;">
<form action="{{ route('kas.index') }}" method="GET">
<h6 class="fw-bold mb-3">Saring Transaksi</h6>
<div class="mb-3 text-start">
<label class="form-label small fw-bold">Jenis Kas</label>
<select name="jenis" class="form-select border-0 bg-light" style="border-radius: 10px;">
<option value="">Semua Jenis</option>
<option value="masuk" {{ request('jenis') == 'masuk' ? 'selected' : '' }}>Pemasukan</option>
<option value="keluar" {{ request('jenis') == 'keluar' ? 'selected' : '' }}>Pengeluaran</option>
</select>
</div>
<div class="mb-3 text-start">
<label class="form-label small fw-bold">Dari Tanggal</label>
<input type="date" name="dari" value="{{ request('dari') }}" class="form-control border-0 bg-light" style="border-radius: 10px;">
</div>
<div class="mb-3 text-start">
<label class="form-label small fw-bold">Sampai Tanggal</label>
<input type="date" name="sampai" value="{{ request('sampai') }}" class="form-control border-0 bg-light" style="border-radius: 10px;">
</div>
<div class="d-grid gap-2 mt-4">
<button type="submit" class="btn btn-primary shadow-sm" style="border-radius: 10px;">Terapkan</button>
<a href="{{ route('kas.index') }}" class="btn btn-link btn-sm text-decoration-none text-muted">Hapus Filter</a>
</div>
</form>
</div>
</div>
<!-- TOMBOL CATAT TRANSAKSI -->
<button type="button" class="btn btn-primary px-4 py-2 shadow-sm pulse-button"
style="border-radius: 12px;" data-bs-toggle="modal" data-bs-target="#modalTambahKas">
<i class="icon-plus me-1"></i> Catat Transaksi
</button>
</div>
</div>
<!-- Label Filter Aktif -->
@if(request('dari') || request('sampai') || request('jenis'))
<div class="mb-3 text-start">
<span class="small text-muted">Filter Aktif: </span>
@if(request('jenis')) <span class="badge bg-primary rounded-pill px-3">{{ strtoupper(request('jenis')) }}</span> @endif
@if(request('dari')) <span class="badge bg-light text-dark border rounded-pill px-3">Sejak: {{ request('dari') }}</span> @endif
<a href="{{ route('kas.index') }}" class="text-danger small ms-2 text-decoration-none"><i class="icon-close"></i> Bersihkan</a>
</div>
@endif
<div class="table-responsive">
<table class="table table-hover align-middle main-table border-0">
<thead>
<tr>
<th width="60" class="text-center">#</th>
<th class="text-start">Keterangan Transaksi</th>
<th class="text-center">Kategori</th>
<th class="text-end">Nominal</th>
<th class="text-end">Sisa Saldo</th>
<th class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
@forelse ($data_kas as $no => $item)
<tr>
<td class="text-center text-muted small">{{ $no + 1 }}</td>
<td class="text-start">
<div class="d-flex align-items-center">
<div class="me-3 bg-{{ $item->jenis == 'masuk' ? 'success' : 'danger' }} rounded-circle p-2" style="width: 10px; height: 10px;"></div>
<div>
<div class="fw-bold text-dark text-start">{{ \Carbon\Carbon::parse($item->tanggal)->format('d/m/Y') }}</div>
<div class="text-muted small text-start">{{ $item->keterangan ?? 'Tanpa keterangan' }}</div>
</div>
</div>
</td>
<td class="text-center">
<span class="badge {{ $item->jenis == 'masuk' ? 'bg-success-soft text-success' : 'bg-danger-soft text-danger' }} border border-{{ $item->jenis == 'masuk' ? 'success' : 'danger' }} px-3 py-2" style="border-radius: 10px; font-size: 10px;">
{{ strtoupper($item->kategori) }}
</span>
</td>
<td class="text-end fw-bold {{ $item->jenis == 'masuk' ? 'text-success' : 'text-danger' }} text-nowrap">
{{ $item->jenis == 'masuk' ? '+' : '-' }} {{ number_format((float)$item->nominal, 0, ',', '.') }}
</td>
<td class="text-end fw-bold text-dark text-nowrap">
Rp {{ number_format((float)$item->saldo_akhir, 0, ',', '.') }}
</td>
<td class="text-center">
<div class="d-flex justify-content-center gap-2">
<!-- Button Edit -->
<button type="button" class="btn-action-custom btn-edit" data-bs-toggle="modal" data-bs-target="#modalEditKas{{ $item->id }}">
<i class="icon-note"></i>
</button>
<!-- Form Hapus -->
<form action="{{ route('kas.destroy', $item->id) }}" method="POST" id="form-hapus-{{ $item->id }}">
@csrf @method('DELETE')
<button type="button" class="btn-action-custom btn-delete" onclick="hapusKas('{{ $item->id }}')">
<i class="icon-trash"></i>
</button>
</form>
</div>
</td>
</tr>
<!-- MODAL EDIT DI DALAM LOOP -->
<div class="modal fade" id="modalEditKas{{ $item->id }}" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow-lg" style="border-radius: 25px;">
<div class="modal-header bg-dark text-white border-0 py-3 px-4" style="border-radius: 25px 25px 0 0;">
<h5 class="modal-title fw-bold"><i class="icon-pencil me-2"></i>Edit Transaksi</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="{{ route('kas.update', $item->id) }}" method="POST">
@csrf @method('PUT')
<div class="modal-body p-4 text-start">
<div class="row g-3">
<div class="col-md-6 text-start">
<label class="form-label small fw-bold">Tanggal</label>
<input type="date" name="tanggal" value="{{ $item->tanggal }}" class="form-control custom-input" required>
</div>
<div class="col-md-6 text-start">
<label class="form-label small fw-bold">Jenis Arus</label>
<select name="jenis" class="form-select custom-input" required>
<option value="masuk" {{ $item->jenis == 'masuk' ? 'selected' : '' }}>Pemasukan (+)</option>
<option value="keluar" {{ $item->jenis == 'keluar' ? 'selected' : '' }}>Pengeluaran (-)</option>
</select>
</div>
<div class="col-12 text-start">
<label class="form-label small fw-bold">Kategori</label>
<input type="text" name="kategori" value="{{ $item->kategori }}" class="form-control custom-input" required>
</div>
<div class="col-12 text-start">
<label class="form-label small fw-bold">Nominal (Rp)</label>
<input type="number" name="nominal" value="{{ (float)$item->nominal }}" class="form-control custom-input" required>
</div>
<div class="col-12 text-start">
<label class="form-label small fw-bold">Keterangan (Opsional)</label>
<textarea name="keterangan" class="form-control custom-input" rows="2">{{ $item->keterangan }}</textarea>
</div>
</div>
</div>
<div class="modal-footer border-0 p-4 pt-0">
<button type="button" class="btn btn-light px-4" data-bs-dismiss="modal" style="border-radius: 12px;">Batal</button>
<button type="submit" class="btn btn-primary px-4 shadow-sm" style="border-radius: 12px;">Update Data</button>
</div>
</form>
</div>
</div>
</div>
@empty
<tr>
<td colspan="6" class="text-center py-5">
<img src="https://illustrations.popsy.co/blue/no-data-found.svg" width="120" alt="no-data">
<p class="text-muted small mt-3">Belum ada transaksi terekam.</p>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Modal Tambah Kas -->
<div class="modal fade" id="modalTambahKas" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow-lg" style="border-radius: 25px;">
<div class="modal-header bg-primary text-white border-0 py-3 px-4" style="border-radius: 25px 25px 0 0;">
<h5 class="modal-title fw-bold"><i class="icon-plus me-2"></i>Catat Transaksi</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="{{ route('kas.store') }}" method="POST">
@csrf
<div class="modal-body p-4 text-start">
<div class="row g-3">
<div class="col-md-6 text-start">
<label class="form-label small fw-bold">Tanggal</label>
<input type="date" name="tanggal" value="{{ date('Y-m-d') }}" class="form-control custom-input" required>
</div>
<div class="col-md-6 text-start">
<label class="form-label small fw-bold">Jenis Arus</label>
<select name="jenis" class="form-select custom-input" required>
<option value="masuk">Pemasukan (+)</option>
<option value="keluar">Pengeluaran (-)</option>
</select>
</div>
<div class="col-12 text-start">
<label class="form-label small fw-bold">Kategori</label>
<input type="text" name="kategori" list="list-kategori-add" class="form-control custom-input" placeholder="Misal: SPP, Listrik" required>
<datalist id="list-kategori-add">
<option value="SPP"><option value="Operasional"><option value="Sumbangan">
</datalist>
</div>
<div class="col-12 text-start">
<label class="form-label small fw-bold">Nominal (Rp)</label>
<input type="number" name="nominal" class="form-control custom-input" placeholder="0" required>
</div>
<div class="col-12 text-start">
<label class="form-label small fw-bold">Keterangan (Opsional)</label>
<textarea name="keterangan" class="form-control custom-input" rows="2"></textarea>
</div>
</div>
</div>
<div class="modal-footer border-0 p-4 pt-0">
<button type="button" class="btn btn-light px-4" data-bs-dismiss="modal" style="border-radius: 12px;">Batal</button>
<button type="submit" class="btn btn-primary px-4 shadow-sm" style="border-radius: 12px;">Simpan Data</button>
</div>
</form>
</div>
</div>
</div>
<style>
.bg-success-soft { background-color: #dcfce7; }
.bg-danger-soft { background-color: #fee2e2; }
.main-table thead th { background-color: #f8fafc; color: #64748b; font-size: 11px; text-transform: uppercase; padding: 15px; border-bottom: 2px solid #f1f5f9; }
.main-table tbody td { padding: 15px; border-bottom: 1px solid #f1f5f9; }
.custom-input { border-radius: 12px; border: 1px solid #e2e8f0; padding: 10px 15px; }
/* Button Action Styling */
.btn-action-custom { width: 32px; height: 32px; border-radius: 8px; border: none; display: flex; align-items: center; justify-content: center; transition: 0.2s; }
.btn-edit { background-color: #e6f7ff; color: #1890ff; }
.btn-edit:hover { background-color: #1890ff; color: white; }
.btn-delete { background-color: #fff1f0; color: #ff4d4f; }
.btn-delete:hover { background-color: #ff4d4f; color: white; }
.pulse-button:hover { animation: pulse 1.5s infinite; }
@keyframes pulse {
0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(13, 110, 253, 0.4); }
70% { transform: scale(1.05); box-shadow: 0 0 0 10px rgba(13, 110, 253, 0); }
100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(13, 110, 253, 0); }
}
</style>
<script>
function hapusKas(id) {
Swal.fire({
title: 'Hapus Transaksi?',
text: "Data akan dihapus permanen dan riwayat saldo akan terpengaruh.",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#dc3545',
confirmButtonText: 'Ya, Hapus!',
borderRadius: '20px'
}).then((result) => { if (result.isConfirmed) { document.getElementById('form-hapus-' + id).submit(); } })
}
</script>
@endsection

View File

@ -7,11 +7,11 @@
<ol class="breadcrumb bg-transparent p-0 mb-2">
<li class="breadcrumb-item"><a href="{{ route('pelatih.index') }}"
class="text-muted text-decoration-none small">Daftar Pelatih</a></li>
<li class="breadcrumb-item active text-primary fw-bold small" aria-current="page">Edit Data Pelatih</li>
<li class="breadcrumb-item active text-primary fw-bold small" aria-current="page">Edit Pelatih</li>
</ol>
</nav>
<h3 class="fw-bold text-dark">Form Edit Data Pelatih</h3>
<p class="text-muted small">Perbarui informasi legalitas SK atau status kepelatihan untuk <strong>{{ $pelatih->nama_lengkap }}</strong>.</p>
<p class="text-muted small">Perbarui profil pribadi dan legalitas SK pelatih <strong>{{ $pelatih->nama_lengkap }}</strong>.</p>
</div>
<div class="row">
@ -22,69 +22,91 @@ class="text-muted text-decoration-none small">Daftar Pelatih</a></li>
<div class="card border-0 shadow-sm mb-4" style="border-radius: 20px;">
<div class="card-header bg-white border-0 pt-4 px-4">
<h5 class="fw-bold text-primary mb-0"><i class="icon-user me-2"></i>Identitas Pelatih</h5>
<h5 class="fw-bold text-primary mb-0"><i class="icon-user me-2"></i>Informasi Akun & Pribadi</h5>
</div>
<div class="card-body p-4">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-bold">Alamat Email (Login)</label>
<input type="email" name="email" class="form-control"
value="{{ old('email', $pelatih->user->email ?? '') }}" required>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Nama Lengkap</label>
<input type="text" name="nama_lengkap" class="form-control"
value="{{ old('nama_lengkap', $pelatih->nama_lengkap) }}" required>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">No Induk</label>
<input type="text" class="form-control bg-light fw-bold"
<input type="text" class="form-control bg-light fw-bold text-primary"
value="{{ $pelatih->no_induk }}" readonly>
<small class="text-muted" style="font-size: 11px;">* No. induk permanen</small>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Nama Lengkap</label>
<input type="text" class="form-control bg-light"
value="{{ $pelatih->nama_lengkap }}" readonly>
<label class="form-label fw-bold">No. WhatsApp</label>
<input type="number" name="no_hp" class="form-control"
value="{{ old('no_hp', $pelatih->no_hp) }}" required>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Asal Kolat</label>
<input type="text" class="form-control bg-light"
value="{{ $pelatih->kolat->nama_kolat ?? '-' }}" readonly>
<label class="form-label fw-bold">Jenis Kelamin</label>
<select name="jenis_kelamin" class="form-select" required>
<option value="L" {{ $pelatih->jenis_kelamin == 'L' ? 'selected' : '' }}>Laki-laki</option>
<option value="P" {{ $pelatih->jenis_kelamin == 'P' ? 'selected' : '' }}>Perempuan</option>
</select>
</div>
<div class="col-md-12">
<label class="form-label fw-bold">Alamat Lengkap</label>
<textarea name="alamat" class="form-control" rows="2" required>{{ old('alamat', $pelatih->alamat) }}</textarea>
</div>
</div>
<small class="text-muted mt-2 d-block">* Data identitas di atas bersifat tetap. Ubah di menu Anggota jika terdapat kesalahan input nama/induk.</small>
</div>
</div>
<div class="card border-0 shadow-sm mb-4" style="border-radius: 20px;">
<div class="card-header bg-white border-0 pt-4 px-4">
<h5 class="fw-bold text-danger mb-0"><i class="icon-certificate me-2"></i>Legalitas & Masa Aktif SK</h5>
<h5 class="fw-bold text-danger mb-0"><i class="icon-badge me-2"></i>Informasi Kepelatihan & SK</h5>
</div>
<div class="card-body p-4">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-bold">Nomor SK Kepelatihan</label>
<input type="text" name="no_sk" class="form-control border-danger"
value="{{ old('no_sk', $pelatih->no_sk) }}" placeholder="Contoh: SK/001/2026" required>
@error('no_sk') <small class="text-danger">{{ $message }}</small> @enderror
<div class="col-md-4">
<label class="form-label fw-bold">Tingkatan Sabuk</label>
<input type="text" name="tingkatan" class="form-control"
value="{{ old('tingkatan', $pelatih->tingkatan) }}" required>
</div>
<div class="col-md-3">
<label class="form-label fw-bold">Tanggal Terbit SK</label>
<input type="date" name="tgl_sk" class="form-control"
value="{{ old('tgl_sk', $pelatih->tgl_sk) }}" required>
</div>
<div class="col-md-3">
<label class="form-label fw-bold">Masa Berlaku</label>
<input type="date" name="masa_berlaku" class="form-control"
value="{{ old('masa_berlaku', $pelatih->masa_berlaku) }}" required>
<div class="col-md-8">
<label class="form-label fw-bold">Asal Kolat (Tempat Melatih)</label>
<select name="kolat_id" class="form-select" required>
@foreach ($data_kolat as $kolat)
<option value="{{ $kolat->id }}" {{ $pelatih->kolat_id == $kolat->id ? 'selected' : '' }}>
{{ $kolat->nama_kolat }}
</option>
@endforeach
</select>
</div>
<div class="col-md-12 mt-4">
<div class="p-3 bg-light rounded-4 border">
<label class="form-label fw-bold d-block">Update Scan SK (Format: JPG, PNG, PDF | Max: 2MB)</label>
<input type="file" name="foto_sk" class="form-control mb-2">
@if ($pelatih->foto_sk)
<div class="d-flex align-items-center mt-2">
<i class="icon-file-text text-primary me-2"></i>
<small class="text-muted">File saat ini:
<a href="{{ asset('storage/' . $pelatih->foto_sk) }}" target="_blank" class="text-decoration-none">
Lihat Dokumen SK <i class="icon-external-link"></i>
</a>
</small>
</div>
@else
<small class="text-warning">Belum ada file SK yang diunggah.</small>
<div class="col-12 mt-3 p-4 bg-light rounded-4 border border-dashed border-danger">
<h6 class="text-danger fw-bold mb-3"><i class="icon-certificate me-2"></i>Legalitas SK Pelatih</h6>
<div class="row g-3">
<div class="col-md-4">
<label class="form-label small fw-bold">Nomor SK</label>
<input type="text" name="no_sk" class="form-control" value="{{ old('no_sk', $pelatih->no_sk) }}">
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Masa Berlaku</label>
<input type="date" name="masa_berlaku" class="form-control" value="{{ $pelatih->masa_berlaku }}">
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Update File SK (PDF/JPG)</label>
<input type="file" name="foto_sk" class="form-control">
</div>
@if($pelatih->foto_sk)
<div class="col-12">
<small class="text-muted">File SK saat ini:
<a href="{{ asset('storage/' . $pelatih->foto_sk) }}" target="_blank" class="text-primary fw-bold text-decoration-none">
Lihat Dokumen <i class="icon-external-link"></i>
</a>
</small>
</div>
@endif
</div>
</div>
@ -92,14 +114,9 @@ class="text-muted text-decoration-none small">Daftar Pelatih</a></li>
</div>
<div class="card-footer bg-light border-0 p-4" style="border-radius: 0 0 20px 20px;">
<div class="d-flex justify-content-end align-items-center gap-3">
<a href="{{ route('pelatih.index') }}"
class="btn btn-outline-secondary px-4 fw-bold btn-cancel">
<i class="icon-x me-1"></i> Batal
</a>
<button type="submit" class="btn btn-primary px-5 fw-bold btn-save shadow">
<i class="icon-check me-1"></i> Simpan Perubahan SK
</button>
<div class="d-flex justify-content-end gap-3">
<a href="{{ route('pelatih.index') }}" class="btn btn-outline-secondary px-4 fw-bold btn-cancel">Batal</a>
<button type="submit" class="btn btn-primary px-5 fw-bold btn-save shadow">Simpan Perubahan Pelatih</button>
</div>
</div>
</div>
@ -109,39 +126,12 @@ class="btn btn-outline-secondary px-4 fw-bold btn-cancel">
</div>
<style>
.form-control,
.form-select {
border-radius: 10px;
padding: 10px 15px;
}
.form-control:focus {
border-color: #0d6efd;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.1);
}
.btn-cancel {
border-radius: 12px;
transition: all 0.3s ease;
border: 2px solid #6c757d;
}
.btn-cancel:hover {
background-color: #6c757d;
color: white;
transform: translateY(-2px);
}
.btn-save {
border-radius: 12px;
background: linear-gradient(45deg, #0d6efd, #004fb1);
border: none;
transition: all 0.3s ease;
}
.btn-save:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(13, 110, 253, 0.4) !important;
}
.form-control, .form-select { border-radius: 10px; padding: 10px 15px; }
.form-control:focus { border-color: #4f46e5; box-shadow: 0 0 0 0.25rem rgba(79, 70, 229, 0.1); }
.rounded-4 { border-radius: 15px !important; }
.btn-cancel { border-radius: 12px; transition: all 0.3s ease; border: 2px solid #6c757d; }
.btn-cancel:hover { background-color: #6c757d; color: white; transform: translateY(-2px); }
.btn-save { border-radius: 12px; background: linear-gradient(45deg, #4f46e5, #3730a3); border: none; transition: all 0.3s ease; }
.btn-save:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(79, 70, 229, 0.4) !important; }
</style>
@endsection

View File

@ -0,0 +1,56 @@
@extends('layout.app')
@section('content')
<div class="container-fluid py-4">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card border-0 shadow-sm" style="border-radius: 20px;">
<div class="card-header bg-white border-0 pt-4 px-4">
<h5 class="fw-bold">Penilaian: <span class="text-primary">{{ $pelatih->nama_lengkap }}</span></h5>
<p class="text-muted small">Kolat: {{ $pelatih->kolat->nama_kolat }} | Periode: {{ now()->format('F Y') }}</p>
</div>
<div class="card-body p-4">
<form action="{{ route('penilaian.store') }}" method="POST">
@csrf
<input type="hidden" name="pelatih_id" value="{{ $pelatih->id }}">
@php
$kriterias = [
'metode_pelatihan' => 'Metode Pelatihan',
'komunikasi' => 'Komunikasi Pelatih & Anggota',
'sikap_kepribadian' => 'Sikap & Kepribadian',
'kepemimpinan' => 'Kepemimpinan',
'konsistensi_komitmen' => 'Konsistensi & Komitmen',
'kedekatan_interpersonal' => 'Kedekatan Interpersonal'
];
@endphp
@foreach($kriterias as $key => $label)
<div class="mb-4 border-bottom pb-3">
<label class="fw-bold d-block mb-2">{{ $label }}</label>
<div class="d-flex gap-3">
@foreach(range(1, 5) as $score)
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="{{ $key }}" id="{{ $key.$score }}" value="{{ $score }}" required>
<label class="form-check-label" for="{{ $key.$score }}">{{ $score }} </label>
</div>
@endforeach
</div>
</div>
@endforeach
<div class="mb-4">
<label class="fw-bold mb-2">Kritik & Saran (Opsional)</label>
<textarea name="kritik_saran" class="form-control" rows="3" placeholder="Tulis masukan Anda di sini..." style="border-radius: 12px;"></textarea>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary py-3 fw-bold" style="border-radius: 12px;">Kirim Penilaian Anonim</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -0,0 +1,133 @@
@extends('layout.app')
@section('content')
<div class="container-fluid py-4">
<div class="page-header mb-4 text-start">
<nav aria-label="breadcrumb">
<ol class="breadcrumb bg-transparent p-0 mb-2">
<li class="breadcrumb-item"><a href="#" class="text-muted text-decoration-none small">Home</a></li>
<li class="breadcrumb-item active text-primary fw-bold small" aria-current="page">Penilaian Pelatih</li>
</ol>
</nav>
<h3 class="fw-bold text-dark">SDM Merpati Putih</h3>
</div>
<div class="row">
<div class="col-12">
<div class="card border-0 shadow-sm" style="border-radius: 20px;">
<div class="card-body p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<div class="text-start">
<h5 class="card-title mb-0 fw-bold text-dark">Evaluasi Kinerja Pelatih</h5>
<p class="text-muted small mb-0">Kelola penilaian bulanan berdasarkan kompetensi pelatih cabang.</p>
</div>
</div>
@if(session('success'))
<div class="alert alert-success border-0 shadow-sm mb-4" style="border-radius: 12px;">
<i class="bi bi-check-circle me-2"></i> {{ session('success') }}
</div>
@endif
<div class="table-responsive">
<table class="table table-hover align-middle main-table text-center">
<thead>
<tr>
<th width="60">No</th>
<th>Identitas Pelatih</th>
<th>No. SK & Masa Berlaku</th>
<th>Kolat</th>
<th>Status SK</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@forelse ($data_pelatih as $no => $item)
<tr>
<td class="text-muted small text-center">{{ $no + 1 }}</td>
<td>
<div class="fw-bold text-dark text-center">{{ $item->nama_lengkap }}</div>
<small class="text-muted d-block text-center">ID: {{ $item->no_induk }}</small>
</td>
<td class="text-center">
<div class="small fw-bold">{{ $item->no_sk ?? '-' }}</div>
<div class="text-muted" style="font-size: 11px;">
Hingga: {{ $item->masa_berlaku ? \Carbon\Carbon::parse($item->masa_berlaku)->format('d M Y') : '-' }}
</div>
</td>
<td class="text-center">
<span class="badge bg-info-soft text-info px-3">{{ $item->kolat->nama_kolat ?? '-' }}</span>
</td>
<td class="text-center">
@php
$isExpired = $item->masa_berlaku ? \Carbon\Carbon::now()->gt($item->masa_berlaku) : true;
@endphp
<span class="badge rounded-pill {{ !$isExpired ? 'bg-success-soft text-success' : 'bg-danger-soft text-danger' }} px-3 border">
{{ !$isExpired ? 'Berlaku' : 'Expired' }}
</span>
</td>
<td class="text-center">
<div class="d-flex justify-content-center gap-2">
<a href="{{ route('penilaian.create', $item->id) }}"
class="btn btn-sm btn-action-evaluate fw-bold px-3 shadow-xs">
<i class="bi bi-star-fill me-1"></i> Beri Nilai
</a>
<a href="{{ route('penilaian.show', $item->id) }}" class="btn btn-sm btn-outline-primary fw-bold px-3 shadow-xs" style="border-radius:10px;">
<i class="bi bi-bar-chart-fill"></i> Rekap
</a>
</div>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="6" class="text-center py-5 text-muted">Data pelatih tidak ditemukan.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.main-table thead th {
background-color: #f8faff;
padding: 18px 10px;
font-size: 0.75rem;
color: #8c98a5;
letter-spacing: 1px;
text-transform: uppercase;
border-bottom: 2px solid #edf2f9;
}
.main-table tbody td {
padding: 20px 10px;
border-bottom: 1px solid #f1f4f8;
color: #495057;
font-size: 0.9rem;
}
.bg-success-soft { background-color: #e6fffa; color: #38b2ac; }
.bg-danger-soft { background-color: #fff5f5; color: #e53e3e; }
.bg-info-soft { background-color: #e0f2fe; color: #0ea5e9; }
/* Style Tombol Beri Nilai (Warna Biru Indigo agar elegan) */
.btn-action-evaluate {
background-color: #eef2ff;
color: #4f46e5;
border: 1px solid #e0e7ff;
border-radius: 10px;
transition: 0.3s;
}
.btn-action-evaluate:hover {
background-color: #4f46e5 !important;
color: white !important;
transform: translateY(-2px);
}
.shadow-xs { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); }
</style>
@endsection

View File

@ -0,0 +1,94 @@
<!DOCTYPE html>
<html>
<head>
<title>Laporan Performa - {{ $pelatih->nama_lengkap }}</title>
<style>
body { font-family: sans-serif; color: #333; line-height: 1.5; }
.header { text-align: center; border-bottom: 2px solid #4f46e5; padding-bottom: 10px; margin-bottom: 20px; }
.header h2 { margin: 0; color: #4f46e5; text-transform: uppercase; }
.header p { margin: 5px 0 0; font-size: 12px; color: #666; }
.info-table { width: 100%; margin-bottom: 20px; font-size: 13px; }
.info-table td { padding: 3px 0; }
.label { font-weight: bold; width: 120px; }
.section-title { background: #f0f2f5; padding: 8px; font-weight: bold; font-size: 14px; margin: 20px 0 10px; border-left: 4px solid #4f46e5; }
table.data-table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
table.data-table th { background: #4f46e5; color: white; text-align: left; padding: 10px; font-size: 12px; }
table.data-table td { padding: 10px; border-bottom: 1px solid #eee; font-size: 12px; }
.bar-container { background: #eee; width: 100%; height: 10px; border-radius: 5px; }
.bar-fill { background: #4f46e5; height: 10px; border-radius: 5px; }
.ulasan-item { padding: 10px; border-bottom: 1px solid #f0f0f0; font-size: 11px; font-style: italic; }
.footer { position: fixed; bottom: 0; width: 100%; text-align: center; font-size: 10px; color: #999; border-top: 1px solid #eee; padding-top: 5px; }
</style>
</head>
<body>
<div class="header">
<h2>LAPORAN EVALUASI PELATIH</h2>
<p>PPS BETAKO MERPATI PUTIH - CABANG JEMBER</p>
</div>
<table class="info-table">
<tr>
<td class="label">Nama Pelatih</td>
<td>: {{ $pelatih->nama_lengkap }}</td>
<td class="label">Periode</td>
<td>: {{ now()->format('F Y') }}</td>
</tr>
<tr>
<td class="label">Unit Latihan</td>
<td>: Kolat {{ $pelatih->kolat->nama_kolat ?? '-' }}</td>
<td class="label">Tanggal Cetak</td>
<td>: {{ now()->format('d/m/Y') }}</td>
</tr>
</table>
<div class="section-title">A. STATISTIK PENILAIAN</div>
<table class="data-table">
<thead>
<tr>
<th>Aspek Penilaian</th>
<th width="50">Skor</th>
<th width="150">Visual</th>
</tr>
</thead>
<tbody>
@php
$scores = [
'Metode Pelatihan' => $rekap->avg_metode,
'Komunikasi' => $rekap->avg_komunikasi,
'Sikap & Etika' => $rekap->avg_sikap,
'Kepemimpinan' => $rekap->avg_kepemimpinan,
'Komitmen' => $rekap->avg_komitmen,
'Interpersonal' => $rekap->avg_interpersonal,
];
@endphp
@foreach($scores as $label => $val)
<tr>
<td>{{ $label }}</td>
<td><strong>{{ number_format($val, 1) }}</strong></td>
<td>
<div class="bar-container">
<div class="bar-fill" style="width: {{ ($val / 5) * 100 }}%;"></div>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
<div class="section-title">B. ULASAN & MASUKAN ANGGOTA</div>
@forelse($ulasan as $text)
<div class="ulasan-item">"{{ $text }}"</div>
@empty
<p style="font-size: 11px; color: #666;">Belum ada ulasan tertulis.</p>
@endforelse
<div class="footer">
Laporan ini dihasilkan secara otomatis oleh Sistem TapakMP - Merpati Putih Jember
</div>
</body>
</html>

View File

@ -0,0 +1,107 @@
@extends('layout.app')
@section('content')
<div class="container-fluid py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h3 class="fw-bold text-dark mb-0">Laporan Performa Pelatih</h3>
<p class="text-muted small">Periode: {{ now()->format('F Y') }}</p>
</div>
<a href="{{ route('penilaian.index') }}" class="btn btn-outline-secondary px-4 shadow-sm" style="border-radius: 12px;">
<i class="bi bi-arrow-left me-2"></i> Kembali
</a>
</div>
<div class="row justify-content-center">
<div class="col-lg-10">
<div class="card border-0 shadow-sm mb-4" style="border-radius: 24px; background: linear-gradient(to right, #4f46e5, #6366f1);">
<div class="card-body p-4">
<div class="d-flex align-items-center">
<img src="https://ui-avatars.com/api/?name={{ urlencode($pelatih->nama_lengkap) }}&background=fff&color=4f46e5&size=128"
class="rounded-circle border border-4 border-white shadow-sm" width="80">
<div class="ms-4 text-white">
<h4 class="fw-bold mb-1">{{ $pelatih->nama_lengkap }}</h4>
<span class="badge bg-white text-primary rounded-pill px-3">Kolat {{ $pelatih->kolat->nama_kolat ?? '-' }}</span>
</div>
</div>
</div>
</div>
<div class="row g-3 mb-4">
@php
$kriteria = [
'metode_pelatihan' => ['label' => 'Metode Pelatihan', 'icon' => 'bi-book', 'color' => '#4f46e5'],
'komunikasi' => ['label' => 'Komunikasi', 'icon' => 'bi-chat-dots', 'color' => '#10b981'],
'sikap_kepribadian' => ['label' => 'Sikap & Etika', 'icon' => 'bi-person-badge', 'color' => '#06b6d4'],
'kepemimpinan' => ['label' => 'Kepemimpinan', 'icon' => 'bi-award', 'color' => '#f59e0b'],
'konsistensi_komitmen' => ['label' => 'Komitmen', 'icon' => 'bi-shield-check', 'color' => '#ef4444'],
'kedekatan_interpersonal' => ['label' => 'Interpersonal', 'icon' => 'bi-people', 'color' => '#6366f1'],
];
$scores = [
'metode_pelatihan' => $rekap->avg_metode,
'komunikasi' => $rekap->avg_komunikasi,
'sikap_kepribadian' => $rekap->avg_sikap,
'kepemimpinan' => $rekap->avg_kepemimpinan,
'konsistensi_komitmen' => $rekap->avg_komitmen,
'kedekatan_interpersonal' => $rekap->avg_interpersonal
];
@endphp
@foreach($kriteria as $key => $attr)
<div class="col-md-4 col-sm-6">
<div class="card border-0 shadow-sm h-100" style="border-radius: 20px;">
<div class="card-body p-3">
<div class="d-flex align-items-center mb-3">
<div class="rounded-circle d-flex align-items-center justify-content-center"
style="width: 40px; height: 40px; background-color: {{ $attr['color'] }}15; color: {{ $attr['color'] }};">
<i class="bi {{ $attr['icon'] }}"></i>
</div>
<span class="ms-2 small fw-bold text-muted uppercase">{{ $attr['label'] }}</span>
</div>
<div class="d-flex align-items-end justify-content-between">
<h3 class="fw-bold mb-0 text-dark">{{ number_format($scores[$key], 1) }}</h3>
<small class="text-muted">/ 5.0</small>
</div>
<div class="progress mt-2" style="height: 6px; border-radius: 10px;">
<div class="progress-bar" style="width: {{ ($scores[$key] / 5) * 100 }}%; background-color: {{ $attr['color'] }}; border-radius: 10px;"></div>
</div>
</div>
</div>
</div>
@endforeach
</div>
<div class="card border-0 shadow-sm" style="border-radius: 24px;">
<div class="card-header bg-transparent border-0 p-4 pb-0">
<h5 class="fw-bold text-dark mb-0"><i class="bi bi-chat-square-quote me-2 text-primary"></i>Kritik & Saran Anggota</h5>
<hr class="mt-3 mb-0">
</div>
<div class="card-body p-4">
<div class="row">
@forelse($ulasan as $teks)
<div class="col-md-6 mb-3">
<div class="p-3 bg-light border-0 h-100 shadow-xs" style="border-radius: 15px;">
<p class="text-dark mb-2 small" style="line-height: 1.5;">"{{ $teks }}"</p>
<small class="text-muted italic" style="font-size: 10px;"> Masukan Anonim</small>
</div>
</div>
@empty
<div class="text-center py-5 w-100">
<p class="text-muted small">Belum ada ulasan tertulis untuk periode ini.</p>
</div>
@endforelse
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.shadow-xs { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02); }
.uppercase { text-transform: uppercase; letter-spacing: 0.5px; }
.italic { font-style: italic; }
.progress { background-color: #f0f2f5; }
</style>
@endsection

View File

@ -0,0 +1,109 @@
@extends('layout.app')
@section('content')
<div class="container-fluid py-4">
<div class="row justify-content-center">
<div class="col-md-8">
<!-- Header Halaman -->
<div class="d-flex align-items-center mb-4">
<a href="{{ route('spp.index') }}" class="btn btn-light shadow-sm me-3" style="border-radius: 10px;">
<i class="fas fa-arrow-left"></i>
</a>
<h3 class="fw-bold text-dark mb-0">Tambah Tagihan SPP Manual</h3>
</div>
<!-- Alert Notifikasi -->
@if(session('error'))
<div class="alert alert-danger border-0 shadow-sm mb-4" style="border-radius: 12px;">
{{ session('error') }}
</div>
@endif
<div class="card border-0 shadow-sm" style="border-radius: 20px;">
<div class="card-body p-4">
<form action="{{ route('spp.store') }}" method="POST">
@csrf
<div class="row g-3">
<!-- Pilih Anggota -->
<div class="col-12">
<label class="form-label small fw-bold">Pilih Anggota</label>
<select name="anggota_id" class="form-select border-0 bg-light py-3 @error('anggota_id') is-invalid @enderror" style="border-radius: 12px;" required>
<option value="" selected disabled>Cari nama anggota...</option>
@foreach($data_anggota as $agt)
<option value="{{ $agt->id }}" {{ old('anggota_id') == $agt->id ? 'selected' : '' }}>
{{ $agt->nama }} (ID: {{ $agt->id }})
</option>
@endforeach
</select>
@error('anggota_id')
<div class="invalid-feedback">{{ $message }}</div>
@enderror
</div>
<!-- Periode Bulan -->
<div class="col-md-6">
<label class="form-label small fw-bold">Untuk Bulan</label>
<select name="bulan" class="form-select border-0 bg-light py-3" style="border-radius: 12px;" required>
@php
$bulanArr = ['Januari','Februari','Maret','April','Mei','Juni','Juli','Agustus','September','Oktober','November','Desember'];
$currentMonth = date('F'); // Default bulan sekarang
@endphp
@foreach($bulanArr as $bln)
<option value="{{ $bln }}" {{ (old('bulan') ?? $bln) == $bln ? 'selected' : '' }}>{{ $bln }}</option>
@endforeach
</select>
</div>
<!-- Periode Tahun -->
<div class="col-md-6">
<label class="form-label small fw-bold">Tahun</label>
<select name="tahun" class="form-select border-0 bg-light py-3" style="border-radius: 12px;" required>
<option value="2025" {{ old('tahun') == '2025' ? 'selected' : '' }}>2025</option>
<option value="2026" {{ (old('tahun') ?? '2026') == '2026' ? 'selected' : '' }}>2026</option>
</select>
</div>
<!-- Nominal -->
<div class="col-md-6">
<label class="form-label small fw-bold">Nominal SPP (Rp)</label>
<input type="number" name="nominal" class="form-control border-0 bg-light py-3"
placeholder="Contoh: 50000" value="{{ old('nominal', 50000) }}" style="border-radius: 12px;" required>
</div>
<!-- Jatuh Tempo -->
<div class="col-md-6">
<label class="form-label small fw-bold">Tanggal Jatuh Tempo</label>
<input type="date" name="jatuh_tempo" class="form-control border-0 bg-light py-3"
value="{{ old('jatuh_tempo', date('Y-m-10')) }}" style="border-radius: 12px;" required>
</div>
<!-- Action Buttons -->
<div class="col-12 mt-4">
<hr class="text-muted opacity-25">
<div class="d-flex justify-content-end gap-2">
<button type="reset" class="btn btn-light px-4 py-2 fw-bold" style="border-radius: 10px;">Reset</button>
<button type="submit" class="btn btn-primary px-4 py-2 fw-bold shadow-sm" style="border-radius: 10px; background-color: #0d6efd;">
<i class="fas fa-save me-1"></i> Simpan Tagihan
</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<style>
.bg-light { background-color: #f8f9fa !important; }
.form-label { color: #555; }
input:focus, select:focus, textarea:focus {
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.1) !important;
background-color: #fff !important;
border: 1px solid #0d6efd !important;
}
</style>
@endsection

View File

@ -0,0 +1,239 @@
@extends('layout.app')
@section('content')
<div class="container-fluid py-4">
<!-- Header Section -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h3 class="fw-bold text-dark mb-1">Manajemen SPP</h3>
<p class="text-muted small mb-0">Kelola tagihan dan pembayaran SPP anggota Merpati Putih.</p>
</div>
<div class="d-flex gap-2">
<form action="{{ route('spp.generate') }}" method="POST">
@csrf
<button type="submit" class="btn btn-warning text-white px-3 py-2 shadow-sm" style="border-radius: 10px;" onclick="return confirm('Generate tagihan otomatis untuk bulan ini?')">
<i class="fas fa-cog me-1"></i> Generate Tagihan
</button>
</form>
<a href="{{ route('spp.create') }}" class="btn btn-danger px-3 py-2 shadow-sm" style="border-radius: 10px; display: flex; align-items: center; text-decoration: none;">
<i class="fas fa-plus me-1"></i> Tambah Manual
</a>
<button class="btn btn-info text-white px-3 py-2 shadow-sm" style="border-radius: 10px; background-color: #0099bc;">
<i class="fas fa-download me-1"></i> Export
</button>
</div>
</div>
<!-- Statistik Cards -->
<div class="row g-3 mb-4">
<div class="col-md-3">
<div class="card border-0 shadow-sm border-start border-success border-4 h-100" style="border-radius: 15px;">
<div class="card-body p-4 d-flex justify-content-between align-items-center">
<div>
<p class="text-success small fw-bold mb-1 uppercase">SPP LUNAS</p>
<h3 class="fw-bold mb-0">{{ $stats['lunas'] }}</h3>
</div>
<i class="fas fa-check-circle text-success fs-1"></i>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm border-start border-warning border-4 h-100" style="border-radius: 15px;">
<div class="card-body p-4 d-flex justify-content-between align-items-center">
<div>
<p class="text-warning small fw-bold mb-1 uppercase">PENDING</p>
<h3 class="fw-bold mb-0">{{ $stats['pending'] }}</h3>
</div>
<i class="fas fa-clock text-warning fs-1"></i>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm border-start border-danger border-4 h-100" style="border-radius: 15px;">
<div class="card-body p-4 d-flex justify-content-between align-items-center">
<div>
<p class="text-danger small fw-bold mb-1 uppercase">BELUM BAYAR</p>
<h3 class="fw-bold mb-0">{{ $stats['belum_bayar'] }}</h3>
</div>
<i class="fas fa-exclamation-triangle text-danger fs-1"></i>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm border-start border-primary border-4 h-100" style="border-radius: 15px;">
<div class="card-body p-4 d-flex justify-content-between align-items-center">
<div>
<p class="text-primary small fw-bold mb-1 uppercase">TOTAL MASUK</p>
<h3 class="fw-bold mb-0">Rp {{ number_format($stats['total_pemasukan'], 0, ',', '.') }}</h3>
</div>
<i class="fas fa-money-bill-wave text-primary fs-1"></i>
</div>
</div>
</div>
</div>
<!-- Filter Data SPP -->
<div class="card border-0 shadow-sm mb-4" style="border-radius: 20px; overflow: hidden;">
<div class="card-header border-0 py-3 text-white" style="background-color: #0d6efd;">
<h6 class="mb-0 fw-bold"><i class="fas fa-filter me-2"></i>Filter Data SPP</h6>
</div>
<div class="card-body p-4">
<form action="{{ route('spp.index') }}" method="GET" class="row g-3 align-items-end">
<div class="col-md-2">
<label class="form-label small fw-bold">Tahun</label>
<select name="tahun" class="form-select border-0 bg-light">
<option value="2026" {{ request('tahun') == '2026' ? 'selected' : '' }}>2026</option>
<option value="2025" {{ request('tahun') == '2025' ? 'selected' : '' }}>2025</option>
</select>
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Bulan</label>
<select name="bulan" class="form-select border-0 bg-light">
<option value="">Semua Bulan</option>
@foreach(['Januari','Februari','Maret','April','Mei','Juni','Juli','Agustus','September','Oktober','November','Desember'] as $m)
<option value="{{ $m }}" {{ request('bulan') == $m ? 'selected' : '' }}>{{ $m }}</option>
@endforeach
</select>
</div>
<div class="col-md-3">
<label class="form-label small fw-bold">Status</label>
<select name="status" class="form-select border-0 bg-light">
<option value="">Semua Status</option>
<option value="lunas" {{ request('status') == 'lunas' ? 'selected' : '' }}>Lunas</option>
<option value="belum_bayar" {{ request('status') == 'belum_bayar' ? 'selected' : '' }}>Belum Bayar</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label small fw-bold">Cari Anggota</label>
<input type="text" name="cari" class="form-control border-0 bg-light" placeholder="Nama anggota..." value="{{ request('cari') }}">
</div>
<div class="col-12 mt-3">
<button type="submit" class="btn btn-primary px-4 shadow-sm" style="background-color: #0d6efd; border-radius: 10px;">
<i class="fas fa-search me-1"></i> Filter
</button>
<a href="{{ route('spp.index') }}" class="btn btn-light px-4 shadow-sm" style="border-radius: 10px;">
<i class="fas fa-sync-alt me-1"></i> Reset
</a>
</div>
</form>
</div>
</div>
<!-- Daftar Tagihan Section -->
<div class="card border-0 shadow-sm" style="border-radius: 20px; overflow: hidden;">
<div class="card-header border-0 py-3 text-white d-flex justify-content-between align-items-center" style="background-color: #0d6efd;">
<h6 class="mb-0 fw-bold"><i class="fas fa-money-check me-2"></i>Daftar Tagihan SPP</h6>
</div>
<div class="card-body p-0">
@if($data_spp->isEmpty())
<div class="py-5 text-center">
<i class="fas fa-file-invoice-dollar text-muted mb-4" style="font-size: 80px; opacity: 0.2;"></i>
<h5 class="fw-bold text-muted">Belum ada data tagihan SPP</h5>
<p class="text-muted small">Silakan tambah manual atau generate otomatis.</p>
<a href="{{ route('spp.create') }}" class="btn btn-danger text-white px-4 py-2 mt-2" style="border-radius: 10px;">Tambah Manual</a>
</div>
@else
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light text-muted uppercase">
<tr>
<th class="ps-4" style="width: 30%;">Anggota</th>
<th>Periode</th>
<th>Nominal</th>
<th>Status</th>
<th class="text-center">Aksi</th>
</tr>
</thead>
<tbody>
@foreach($data_spp as $spp)
<tr>
<td class="ps-4">
<div class="d-flex align-items-center">
<!-- Avatar Inisial -->
<div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center me-3 shadow-sm"
style="width: 40px; height: 40px; font-size: 14px; font-weight: bold; background: linear-gradient(45deg, #0d6efd, #0099bc);">
{{ strtoupper(substr($spp->anggota->nama, 0, 1)) }}
</div>
<div>
<div class="fw-bold text-dark" style="font-size: 0.95rem;">{{ $spp->anggota->nama }}</div>
<span class="badge bg-light text-muted border fw-normal" style="font-size: 0.75rem;">
ID: {{ $spp->anggota_id }}
</span>
</div>
</div>
</td>
<td>
<div class="text-dark fw-medium">{{ $spp->bulan }}</div>
<div class="small text-muted">{{ $spp->tahun }}</div>
</td>
<td class="fw-bold text-dark">
Rp {{ number_format($spp->nominal, 0, ',', '.') }}
</td>
<td>
@if($spp->status == 'lunas')
<span class="badge bg-success-soft text-success rounded-pill px-3">
<i class="fas fa-check-circle me-1"></i> Lunas
</span>
@elseif($spp->status == 'belum_bayar' && \Carbon\Carbon::parse($spp->jatuh_tempo)->isPast())
<span class="badge bg-danger-soft text-danger rounded-pill px-3">
<i class="fas fa-exclamation-circle me-1"></i> Terlambat
</span>
@else
<span class="badge bg-warning-soft text-warning rounded-pill px-3">
<i class="fas fa-clock me-1"></i> Belum Bayar
</span>
@endif
</td>
<td class="text-center">
@if($spp->status != 'lunas')
<form action="{{ route('spp.bayar', $spp->id) }}" method="POST" class="d-inline">
@csrf
<button type="submit" class="btn btn-sm btn-primary px-3 shadow-sm"
style="border-radius: 8px;"
onclick="return confirm('Konfirmasi pembayaran untuk {{ $spp->anggota->nama }}?')">
Bayar
</button>
</form>
@else
<span class="text-success small fw-bold">
<i class="fas fa-check-double me-1"></i> Terbayar
</span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
</div>
</div>
</div>
<style>
.bg-light { background-color: #f8f9fa !important; }
.uppercase { text-transform: uppercase; letter-spacing: 0.8px; font-size: 10px; font-weight: 700; }
.fs-1 { font-size: 2.2rem !important; opacity: 0.2; }
/* Soft Badge Styles */
.bg-success-soft { background-color: rgba(25, 135, 84, 0.12); }
.bg-danger-soft { background-color: rgba(220, 53, 69, 0.12); }
.bg-warning-soft { background-color: rgba(255, 193, 7, 0.15); }
.table-hover tbody tr:hover {
background-color: rgba(13, 110, 253, 0.03);
transition: 0.2s;
}
.form-select, .form-control {
border-radius: 10px;
padding: 0.6rem 1rem;
}
.card {
transition: transform 0.2s;
}
</style>
@endsection

View File

@ -4,9 +4,12 @@
use App\Http\Controllers\AuthController;
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\JadwalController;
use App\Http\Controllers\KasController;
use App\Http\Controllers\KolatController;
use App\Http\Controllers\PelatihController;
use App\Http\Controllers\PenilaianController;
use App\Http\Controllers\PresensiController;
use App\Http\Controllers\SppController;
use Illuminate\Support\Facades\Route;
@ -103,3 +106,30 @@
Route::post('/tambah-manual', [PresensiController::class, 'storeManual'])->name('storeManual');
});
//Penialaian
Route::prefix('penilaian')->name('penilaian.')->group(function () {
Route::get('/', [PenilaianController::class, 'index'])->name('index');
// Hilangkan kata 'penilaian' di dalam sini karena sudah ada di prefix
Route::get('/create/{id}', [PenilaianController::class, 'create'])->name('create');
Route::post('/store', [PenilaianController::class, 'store'])->name('store');
Route::get('/penilaian/rekap/{id}', [PenilaianController::class, 'show'])->name('show');
});
//Kas
Route::prefix('kas')->name('kas.')->group(function () {
Route::get('/', [KasController::class, 'index'])->name('index');
Route::post('/store', [KasController::class, 'store'])->name('store');
Route::put('/update/{id}', [KasController::class, 'update'])->name('update');
Route::delete('/{id}', [KasController::class, 'destroy'])->name('destroy');
});
// Group SPP
Route::prefix('spp')->name('spp.')->group(function () {
Route::get('/', [SppController::class, 'index'])->name('index');
Route::get('/create', [SppController::class, 'create'])->name('create');
Route::post('/store', [SppController::class, 'store'])->name('store');
Route::post('/bayar/{id}', [SppController::class, 'bayar'])->name('bayar');
Route::post('/generate', [SppController::class, 'generateTagihan'])->name('generate');
});