This commit is contained in:
ell 2026-06-09 21:05:50 +07:00
parent 54a4a3a44b
commit 1f9a350251
15 changed files with 487 additions and 141 deletions

View File

@ -58,6 +58,7 @@ public function create()
$data_pelatih = Anggota::whereHas('roles', function($query) {
$query->where('nama_role', 'Pelatih');
})
->with('kolatLatihan')
->where('status', 'Aktif')
->orderBy('nama_lengkap', 'asc')
->get();
@ -100,7 +101,11 @@ public function edit($id)
// Tetap filter agar hanya muncul daftar pelatih
$data_pelatih = Anggota::whereHas('roles', function($query) {
$query->where('nama_role', 'Pelatih');
})->get();
})
->with('kolatLatihan')
->where('status', 'Aktif')
->orderBy('nama_lengkap', 'asc')
->get();
return view('jadwal.editjadwal', compact('jadwal', 'data_kolat', 'data_pelatih'));
}

View File

@ -79,7 +79,9 @@ public function store(Request $request)
$updateData['foto_sk'] = $path;
}
$anggota->roles()->syncWithoutDetaching([$rolePelatih->id]);
// $anggota->roles()->syncWithoutDetaching([$rolePelatih->id]);
// KODE BARU (Benar karena akan mengganti role Anggota menjadi murni Pelatih)
$anggota->roles()->sync([$rolePelatih->id]);
$anggota->kolatLatihan()->sync($request->kolat_ids);
// Eksekusi Update

View File

@ -67,19 +67,19 @@ public function boot(): void
// C. Kandidat Pelatih Baru (Kriteria: Usia >= 18 & Tingkatan Balik 1)
// Kita hitung menggunakan Carbon untuk tanggal lahir
$kandidatPelatih = Anggota::where('tingkatan', 'Balik 1')
->where('status', 'Aktif')
->where('tgl_lahir', '<=', Carbon::now()->subYears(18))
->count();
// $kandidatPelatih = Anggota::where('tingkatan', 'Balik 1')
// ->where('status', 'Aktif')
// ->where('tgl_lahir', '<=', Carbon::now()->subYears(18))
// ->count();
if ($kandidatPelatih > 0) {
$notifications[] = [
'icon' => 'bi-star-fill text-info',
'title' => 'Kandidat Pelatih',
'msg' => "Ada $kandidatPelatih anggota Balik 1 berusia 18th siap jadi Pelatih.",
'link' => route('anggota.anggota') // Bisa diarahkan ke daftar anggota filter Balik 1
];
}
// if ($kandidatPelatih > 0) {
// $notifications[] = [
// 'icon' => 'bi-star-fill text-info',
// 'title' => 'Kandidat Pelatih',
// 'msg' => "Ada $kandidatPelatih anggota Balik 1 berusia 18th siap jadi Pelatih.",
// 'link' => route('anggota.anggota') // Bisa diarahkan ke daftar anggota filter Balik 1
// ];
// }
// D. Peringatan Saldo Kas Kritis (< 500rb)
$saldo = Kas::sum('nominal');

View File

@ -13,11 +13,29 @@ class KolatSeeder extends Seeder
*/
public function run(): void
{
// Menghapus data lama agar tidak bentrok saat migrate:fresh --seed
DB::table('kolat')->delete();
DB::table('kolat')->insert([
'id' => 1, // Kita paksa ID 1 biar nyambung sama UserSeeder tadi
[
'id' => 1, // Wajib ID 1 agar nyambung dengan UserSeeder (Siti, Budi, Andi)
'nama_kolat' => 'Kolat Unej',
'created_at' => now(),
'updated_at' => now(),
],
[
'id' => 2,
'nama_kolat' => 'Kolat Matasa',
'created_at' => now(),
'updated_at' => now(),
],
[
'id' => 3,
'nama_kolat' => 'Kolat Ajung',
'created_at' => now(),
'updated_at' => now(),
]
]);
}
}

View File

@ -16,42 +16,97 @@ class UserSeeder extends Seeder
*/
public function run(): void
{
// 1. Ambil ID Role Pelatih
$rolePelatih = Role::where('nama_role', 'Pelatih')->first();
$rolePengurus = Role::where('nama_role', 'Pengurus')->first();
$rolePelatih = Role::where('nama_role', 'Pelatih')->first();
$roleAnggota = Role::where('nama_role', 'Anggota')->first();
// 2. Buat Akun User untuk Pelatih
$user = User::create([
'email' => 'pelatih@tapakmp.com',
'password' => Hash::make('password123'), // Password default
// ==========================================================
// AKUN 1: PENGURUS (Akun kamu: Super Admin = Pelatih + Pengurus)
// ==========================================================
$userPengurus = User::create([
'email' => 'pengurus@tapakmp.com',
'password' => Hash::make('password123'),
]);
// 3. Buat Profil Anggota untuk User tersebut
$anggota = Anggota::create([
'user_id' => $user->id,
$anggotaPengurus = Anggota::create([
'user_id' => $userPengurus->id,
'no_induk' => 'MP-2026-001',
'nama_lengkap' => 'Siti Afiah Dahliawati',
'jenis_kelamin' => 'P',
'tempat_lahir' => 'Jember',
'tgl_lahir' => '2004-10-29',
'no_hp' => '081455057453',
'kolat_id' => 1, // Menyambung ke Kolat Unej di KolatSeeder
'kolat_id' => 1, // Pastikan ada data Kolat dengan ID 1
'tingkatan' => 'Balik 1',
'tgl_gabung' => now(),
'status' => 'Aktif',
'alamat' => 'Jl. Merpati Putih No. 1, Jember',
'jabatan' => 'Pelatih, Pengurus Kolat',
'jabatan' => 'Pengurus (Ketua)',
]);
// 4. INI BAGIAN TERPENTING: Masukkan data ke tabel pivot anggota_role!
// Perintah attach() ini akan otomatis mengisi tabel anggota_role dengan anggota_id dan role_id
if ($rolePelatih) {
$anggota->roles()->attach($rolePelatih->id);
}
// Menempelkan peran sebagai Pengurus (Menjadikannya akun super ganda untuk kebutuhan pengetesan)
// Tempelkan HANYA peran Pengurus
if ($rolePengurus) {
$anggota->roles()->attach($rolePengurus->id);
$anggotaPengurus->roles()->attach($rolePengurus->id);
}
// ==========================================================
// AKUN 2: PELATIH (Hanya bisa akses menu kepelatihan)
// ==========================================================
$userPelatih = User::create([
'email' => 'pelatih@tapakmp.com',
'password' => Hash::make('password123'),
]);
$anggotaPelatih = Anggota::create([
'user_id' => $userPelatih->id,
'no_induk' => 'MP-2026-002',
'nama_lengkap' => 'Budi Santoso',
'jenis_kelamin' => 'L',
'tempat_lahir' => 'Banyuwangi',
'tgl_lahir' => '2000-05-15',
'no_hp' => '081234567890',
'kolat_id' => 1,
'tingkatan' => 'Kombinasi 1',
'tgl_gabung' => now()->subYears(2),
'status' => 'Aktif',
'alamat' => 'Jl. Mastrip, Jember',
'jabatan' => 'Pelatih',
]);
// Tempelkan peran Pelatih
if ($rolePelatih) {
$anggotaPelatih->roles()->attach($rolePelatih->id);
}
// Hubungkan pelatih dengan Kolat (1 = Unej)
$anggotaPelatih->kolatLatihan()->attach([1]);
// ==========================================================
// AKUN 3: ANGGOTA (Hanya bisa akses dashboard anggota, presensi, spp)
// ==========================================================
$userAnggota = User::create([
'email' => 'anggota@tapakmp.com',
'password' => Hash::make('password123'),
]);
$anggotaBiasa = Anggota::create([
'user_id' => $userAnggota->id,
'no_induk' => 'MP-2026-003',
'nama_lengkap' => 'Siti Nurul Amalia',
'jenis_kelamin' => 'P',
'tempat_lahir' => 'Jember',
'tgl_lahir' => '2005-08-20',
'no_hp' => '085712345678',
'kolat_id' => 1,
'tingkatan' => 'Dasar 1',
'tgl_gabung' => now()->subMonths(3),
'status' => 'Aktif',
'alamat' => 'Jl. Kalimantan, Jember',
'jabatan' => 'Anggota',
]);
// Tempelkan hanya peran Anggota
if ($roleAnggota) {
$anggotaBiasa->roles()->attach($roleAnggota->id);
}
}

View File

@ -46,13 +46,24 @@
<div class="col-md-6 mb-3">
<label class="form-label fw-bold text-dark">Pelatih Bertugas</label>
<select name="pelatih_id" class="form-select @error('pelatih_id') is-invalid @enderror" required>
{{-- <select name="pelatih_id" class="form-select @error('pelatih_id') is-invalid @enderror" required>
<option value="" selected disabled>Pilih Pelatih</option>
@foreach($data_pelatih as $pelatih)
<option value="{{ $pelatih->id }}" {{ old('pelatih_id') == $pelatih->id ? 'selected' : '' }}>
{{ $pelatih->nama_lengkap }} ({{ $pelatih->no_induk }})
</option>
@endforeach
</select> --}}
<select name="pelatih_id" class="form-select @error('pelatih_id') is-invalid @enderror" required>
<option value="" selected disabled>Pilih Pelatih</option>
@foreach($data_pelatih as $pelatih)
{{-- Menyisipkan kumpulan ID Kolat milik pelatih ke dalam atribut data-kolats --}}
<option value="{{ $pelatih->id }}"
data-kolats="{{ json_encode($pelatih->kolatLatihan->pluck('id')->toArray()) }}"
{{ old('pelatih_id') == $pelatih->id ? 'selected' : '' }}>
{{ $pelatih->nama_lengkap }} ({{ $pelatih->no_induk }})
</option>
@endforeach
</select>
@error('pelatih_id')
<div class="invalid-feedback">{{ $message }}</div>
@ -161,4 +172,50 @@
margin-bottom: 0.5rem;
}
</style>
{{-- SCRIPT FILTER PELATIH BERDASARKAN KOLAT --}}
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
$(document).ready(function() {
const pelatihSelect = $('select[name="pelatih_id"]');
// Kloning seluruh elemen opsi pelatih bawaan sebagai master copy
const masterPelatih = pelatihSelect.find('option').clone();
$('select[name="kolat_id"]').change(function() {
const kolatId = $(this).val();
// Bersihkan dropdown pelatih
pelatihSelect.empty();
pelatihSelect.append('<option value="" selected disabled>Pilih Pelatih</option>');
if (kolatId) {
// Iterasi dan filter opsi pelatih dari master copy
masterPelatih.each(function() {
const kolats = $(this).data('kolats'); // Membaca array dari data-kolats
// Jika pelatih bertugas di kolat yang dipilih, lampirkan kembali opsi ke dropdown
if (kolats && kolats.includes(parseInt(kolatId))) {
pelatihSelect.append($(this).clone());
}
});
} else {
// Jika pilihan kolat kosong/direset, tampilkan semua pelatih kembali
masterPelatih.each(function() {
if ($(this).val() !== "") {
pelatihSelect.append($(this).clone());
}
});
}
});
// Trigger otomatis saat halaman dimuat (untuk old input)
const initialKolat = $('select[name="kolat_id"]').val();
if (initialKolat) {
const currentPelatih = "{{ old('pelatih_id') }}";
$('select[name="kolat_id"]').trigger('change');
if (currentPelatih) {
pelatihSelect.val(currentPelatih);
}
}
});
</script>
@endsection

View File

@ -1,6 +1,11 @@
@extends('layout.app')
@section('content')
@php
$user = auth()->user();
$userRoles = $user && $user->anggota ? $user->anggota->roles->pluck('nama_role')->toArray() : [];
$isPengurus = in_array('Pengurus', $userRoles);
@endphp
<div class="container-fluid py-4">
<!-- Header & Breadcrumb -->
<div class="page-header mb-4 text-start">
@ -21,13 +26,16 @@
<!-- Title & Action Button -->
<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">Daftar Kolat Pada PPS Betako Merpati Putih</h5>
<h5 class="card-title mb-0 fw-bold text-dark">Daftar Kolat Pada PPS Betako Merpati Putih
</h5>
<p class="text-muted small mb-0">Cabang Jember - Kelola lokasi dan unit latihan.</p>
</div>
@if ($isPengurus)
<a href="{{ route('kolat.create') }}" class="btn btn-primary px-4 py-2 shadow-sm"
style="border-radius: 12px;">
<i class="bi bi-plus-lg me-1"></i> Tambah Kolat
</a>
@endif
</div>
<!-- Notifikasi Alert (Opsional jika ingin pakai SweetAlert saja, ini bisa dihapus) -->
@ -44,7 +52,9 @@
<th width="80">ID</th>
<th>Nama Kelompok Latihan</th>
<th>Alamat Lokasi</th>
@if ($isPengurus)
<th width="200">Aksi</th>
@endif
</tr>
</thead>
<tbody>
@ -57,31 +67,35 @@
</td>
<td class="text-center">
<span class="text-muted small">
<i class="bi bi-geo-alt me-1"></i> {{ $item->alamat_kolat ?? 'Alamat belum diatur' }}
<i class="bi bi-geo-alt me-1"></i>
{{ $item->alamat_kolat ?? 'Alamat belum diatur' }}
</span>
</td>
@if ($isPengurus)
<td class="text-center">
<div class="d-flex justify-content-center gap-2">
<!-- Edit Button -->
<a href="{{ route('kolat.edit', $item->id) }}"
class="btn btn-sm btn-action-edit fw-bold px-3 shadow-xs">
<i class="bi bi-pencil-square"></i>
</a>
<!-- Delete Button dengan SweetAlert -->
<form action="{{ route('kolat.destroy', $item->id) }}" method="POST" id="delete-form-{{ $item->id }}">
<form action="{{ route('kolat.destroy', $item->id) }}"
method="POST" id="delete-form-{{ $item->id }}">
@csrf
@method('DELETE')
<button type="button" onclick="confirmDelete({{ $item->id }})" class="btn btn-sm btn-action-delete fw-bold px-3 shadow-xs">
<button type="button"
onclick="confirmDelete({{ $item->id }})"
class="btn btn-sm btn-action-delete fw-bold px-3 shadow-xs">
<i class="bi bi-trash"></i>
</button>
</form>
</div>
</td>
@endif
</tr>
@empty
<tr>
<td colspan="4" class="text-center py-5">
<td colspan="{{ $isPengurus ? '4' : '3' }}" class="text-center py-5">
<p class="text-muted">Belum ada data kolat yang tersedia.</p>
</td>
</tr>
@ -97,7 +111,11 @@ class="btn btn-sm btn-action-edit fw-bold px-3 shadow-xs">
</div>
<style>
.main-table { text-align: center; vertical-align: middle; }
.main-table {
text-align: center;
vertical-align: middle;
}
.main-table thead th {
background-color: #f8faff;
padding: 18px 10px;
@ -107,12 +125,14 @@ class="btn btn-sm btn-action-edit fw-bold px-3 shadow-xs">
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;
}
.btn-action-edit {
background-color: #fff8e6;
color: #f59e0b;
@ -120,11 +140,13 @@ class="btn btn-sm btn-action-edit fw-bold px-3 shadow-xs">
border-radius: 10px;
transition: 0.3s;
}
.btn-action-edit:hover {
background-color: #f59e0b !important;
color: white !important;
transform: translateY(-2px);
}
.btn-action-delete {
background-color: #fff5f5;
color: #dc3545;
@ -132,12 +154,16 @@ class="btn btn-sm btn-action-edit fw-bold px-3 shadow-xs">
border-radius: 10px;
transition: 0.3s;
}
.btn-action-delete:hover {
background-color: #dc3545 !important;
color: white !important;
transform: translateY(-2px);
}
.shadow-xs { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); }
.shadow-xs {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
</style>
@push('scripts')

View File

@ -1,4 +1,4 @@
<footer id="footer" class="footer">
{{-- <footer id="footer" class="footer">
<div class="copyright">
&copy; Copyright <strong><span>TapakMP</span></strong>. All Rights Reserved
</div>
@ -9,4 +9,4 @@
<!-- Purchase the pro version with working PHP/AJAX contact form: https://bootstrapmade.com/nice-admin-bootstrap-admin-html-template/ -->
Designed by <a href="https://bootstrapmade.com/">BootstrapMade</a>
</div>
</footer>
</footer> --}}

View File

@ -8,12 +8,12 @@
<i class="bi bi-list toggle-sidebar-btn"></i>
</div><!-- End Logo -->
<div class="search-bar">
{{-- <div class="search-bar">
<form class="search-form d-flex align-items-center" method="POST" action="#">
<input type="text" name="query" placeholder="Search" title="Enter search keyword">
<button type="submit" title="Search"><i class="bi bi-search"></i></button>
</form>
</div><!-- End Search Bar -->
</div><!-- End Search Bar --> --}}
<nav class="header-nav ms-auto">
<ul class="d-flex align-items-center">

View File

@ -34,6 +34,17 @@
@endif
</li>
@if($userRole === 'Pengurus')
<li class="nav-item">
{{-- Diubah agar mengarah ke rute pengurus dan mendeteksi status aktif dengan benar --}}
<a class="nav-link {{ request()->routeIs('pengurus.*') ? '' : 'collapsed' }}" href="{{ route('pengurus.index') }}">
<i class="bi bi-shield-lock"></i>
<span>Data Pengurus</span>
</a>
</li>
@endif
{{-- ======================================================== --}}
{{-- MENU MANAJEMEN ANGGOTA (Hanya Pelatih & Pengurus) --}}
{{-- ======================================================== --}}

View File

@ -152,6 +152,8 @@ class="text-muted text-decoration-none small">Daftar Pelatih</a></li>
</div>
</div>
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" />
<style>
.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); }
@ -160,6 +162,34 @@ class="text-muted text-decoration-none small">Daftar Pelatih</a></li>
.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; }
/* CUSTOM CSS UNTUK SELECT2 AGAR RAPI DAN MELENGKUNG SAMA DENGAN FORM LAIN */
.select2-container--bootstrap-5 .select2-selection {
border-radius: 10px;
min-height: 45px;
padding: 5px 10px;
border: 1px solid #ced4da;
}
.select2-container--bootstrap-5.select2-container--focus .select2-selection {
border-color: #4f46e5;
box-shadow: 0 0 0 0.25rem rgba(79, 70, 229, 0.1);
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice {
background-color: #4f46e5;
color: white;
border: none;
border-radius: 8px;
padding: 2px 10px;
margin-top: 5px;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove {
color: white;
margin-right: 8px;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove:hover {
color: #ff4d4d;
background: none;
}
</style>
@push('scripts')

View File

@ -82,14 +82,57 @@
</div>
</div>
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" />
<style>
/* CUSTOM CSS UNTUK SELECT2 AGAR MELENGKUNG 12PX (Sama dengan input lain) */
.select2-container--bootstrap-5 .select2-selection {
border-radius: 12px;
min-height: 48px;
padding: 5px 10px;
border: 1px solid #ced4da;
}
/* Warna saat input di-klik (Focus) */
.select2-container--bootstrap-5.select2-container--focus .select2-selection {
border-color: #0d6efd;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.1);
}
/* Desain untuk mode "Multiple" (Banyak Kolat) */
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice {
background-color: #0d6efd; /* Warna biru primary */
color: white;
border: none;
border-radius: 8px;
padding: 2px 10px;
margin-top: 6px;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove {
color: white;
margin-right: 8px;
}
.select2-container--bootstrap-5 .select2-selection--multiple .select2-selection__choice__remove:hover {
color: #ff4d4d;
background: none;
}
/* Penyesuaian tinggi teks untuk mode "Single" (Pilih Anggota) */
.select2-container--bootstrap-5 .select2-selection--single .select2-selection__rendered {
padding-top: 4px;
}
</style>
<!-- Tambahkan script Select2 di layout utama atau di sini -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
$('.select2').select2({
theme: 'bootstrap-5',
placeholder: "Klik untuk memilih Kolat...",
placeholder: "Klik untuk mencari dan memilih...",
allowClear: true,
width: '100%' // Memastikan dropdown memenuhi lebar kolom
width: '100%'
});
});
</script>

View File

@ -30,46 +30,57 @@
@if(session('success'))
<div class="alert alert-success alert-dismissible fade show border-0 mb-3 shadow-sm" style="border-radius: 10px;">
{{ session('success') }}
<i class="bi bi-check-circle-fill me-2"></i>{{ session('success') }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
<div class="table-responsive">
<table class="table table-hover align-middle main-table text-center">
<thead>
<table class="table table-hover align-middle main-table text-center mb-0">
<thead class="bg-light text-muted">
<tr>
<th width="60">No</th>
<th>Identitas Pengurus</th>
<th>No. HP / WhatsApp</th>
<th>Jabatan & Peran Sistem</th>
<th>Status Akun</th>
<th>Aksi</th>
<th width="5%" class="py-3 ps-3">No</th>
<th width="25%" class="py-3">Identitas Pengurus</th>
<th width="20%" class="py-3">No. HP / WhatsApp</th>
<th width="25%" class="py-3">Jabatan & Peran Sistem</th>
<th width="15%" class="py-3">Status Akun</th>
<th width="10%" class="py-3 pe-3">Aksi</th>
</tr>
</thead>
<tbody>
@forelse ($data_pengurus as $no => $item)
<tr>
<td class="text-muted small text-center">{{ $no + 1 }}</td>
<td class="text-muted small ps-3">{{ $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>
<div class="fw-bold text-dark" style="font-size: 0.95rem;">{{ $item->nama_lengkap }}</div>
<small class="text-muted d-block">ID: {{ $item->no_induk }}</small>
</td>
<td>{{ $item->no_hp }}</td>
<td>
<div class="fw-bold text-primary mb-1">{{ ucwords($item->jabatan) }}</div>
<span class="text-dark">{{ $item->no_hp ?? '-' }}</span>
</td>
<td>
<div class="d-flex flex-wrap gap-1 justify-content-center">
@foreach($item->roles as $role)
<span class="badge bg-secondary-soft text-secondary px-2 py-1 small" style="font-size: 10px;">{{ $role->nama_role }}</span>
@endforeach
</td>
<td class="text-center">
<span class="badge rounded-pill bg-success-soft text-success px-3 border">
{{ $item->status }}
<span class="badge bg-primary-soft text-primary px-2 py-1 fw-semibold" style="font-size: 0.75rem; border-radius: 6px;">
{{ $role->nama_role }}
</span>
@endforeach
</div>
</td>
<td class="text-center">
<td>
@if($item->status == 'Aktif')
<span class="badge bg-success-soft text-success px-3 py-2 rounded-pill fw-bold border border-success-subtle" style="font-size: 0.75rem;">
<i class="bi bi-check-circle-fill me-1"></i> Aktif
</span>
@else
<span class="badge bg-danger-soft text-danger px-3 py-2 rounded-pill fw-bold border border-danger-subtle" style="font-size: 0.75rem;">
<i class="bi bi-x-circle-fill me-1"></i> Non-Aktif
</span>
@endif
</td>
<td class="pe-3">
<div class="d-flex justify-content-center gap-2">
<a href="{{ route('pengurus.edit', $item->id) }}" class="btn btn-sm btn-action-edit fw-bold px-2 shadow-xs">
<a href="{{ route('pengurus.edit', $item->id) }}" class="btn btn-sm btn-action-edit fw-bold px-3 shadow-xs" title="Edit Pengurus">
<i class="bi bi-pencil"></i>
</a>
</div>
@ -77,7 +88,10 @@
</tr>
@empty
<tr>
<td colspan="6" class="text-muted py-4">Belum ada anggota yang diangkat menjadi pengurus struktural.</td>
<td colspan="6" class="text-center py-5 text-muted">
<i class="bi bi-folder-x mb-3 d-block" style="font-size: 3rem; opacity: 0.3;"></i>
<h6 class="fw-bold">Belum ada anggota yang diangkat menjadi pengurus struktural.</h6>
</td>
</tr>
@endforelse
</tbody>
@ -91,12 +105,48 @@
</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-secondary-soft { background-color: #f1f5f9; color: #475569; }
.btn-action-edit { background-color: #fff8e6; color: #f59e0b; border: 1px solid #ffecb3; border-radius: 10px; transition: 0.3s; }
.btn-action-edit:hover { background-color: #f59e0b !important; color: white !important; transform: translateY(-2px); }
.main-table thead th {
background-color: #f8faff;
font-size: 0.75rem;
color: #8c98a5;
letter-spacing: 1px;
text-transform: uppercase;
border-bottom: 2px solid #edf2f9;
}
.main-table tbody td {
padding: 16px 10px;
border-bottom: 1px solid #f1f4f8;
color: #495057;
font-size: 0.9rem;
}
.main-table tbody tr:hover {
background-color: #f8faff;
transition: 0.2s;
}
/* WARNA BADGE CUSTOM */
.bg-primary-soft { background-color: #e0f2fe; }
.text-primary { color: #0ea5e9 !important; }
.bg-success-soft { background-color: #d1e7dd; }
.text-success { color: #0f5132 !important; }
.bg-danger-soft { background-color: #f8d7da; }
.text-danger { color: #842029 !important; }
/* ANIMASI TOMBOL EDIT */
.btn-action-edit {
background-color: #fff8e6;
color: #f59e0b;
border: 1px solid #ffecb3;
border-radius: 10px;
transition: 0.3s;
}
.btn-action-edit:hover {
background-color: #f59e0b !important;
color: white !important;
transform: translateY(-2px);
}
.shadow-xs { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); }
</style>
@endsection

View File

@ -2,7 +2,9 @@
@section('content')
@php
$userRole = auth()->user()->role->nama_role ?? 'Anggota';
$user = auth()->user();
// Ambil semua role yang dimiliki user ke dalam bentuk array
$userRoles = $user && $user->anggota ? $user->anggota->roles->pluck('nama_role')->toArray() : [];
@endphp
<div class="container-fluid py-4">
@ -14,7 +16,7 @@
</div>
<div class="d-flex flex-wrap gap-2">
{{-- HANYA PENGURUS YANG BISA GENERATE MASAL --}}
@if ($userRole == 'Pengurus')
@if (in_array('Pengurus', $userRoles))
<form action="{{ route('spp.generate') }}" method="POST" class="m-0" id="formGenerateSpp">
@csrf
<button type="button"
@ -229,13 +231,26 @@ class="btn btn-danger px-3 py-2 shadow-sm d-flex align-items-center"
</td>
<td class="text-center">
@if ($spp->status == 'belum_bayar')
<form action="{{ route('spp.bayar', $spp->id) }}" method="POST"
{{-- <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 tunai untuk {{ $spp->anggota->nama_lengkap }}?')">
@if ($userRole == 'Pelatih')
@if (in_array('Pelatih', $userRoles))
<i class="fas fa-hand-holding-usd me-1"></i> Terima Cash
@else
Bayar Tunai
@endif
</button>
</form> --}}
<form action="{{ route('spp.bayar', $spp->id) }}" method="POST" class="d-inline" id="formBayarTunai-{{ $spp->id }}">
@csrf
<button type="button" class="btn btn-sm btn-primary px-3 shadow-sm"
style="border-radius: 8px;"
onclick="konfirmasiBayarTunai({{ $spp->id }}, '{{ addslashes($spp->anggota->nama_lengkap) }}')">
@if (in_array('Pelatih', $userRoles))
<i class="fas fa-hand-holding-usd me-1"></i> Terima Cash
@else
Bayar Tunai
@ -252,7 +267,19 @@ class="btn btn-sm btn-info text-white px-2 shadow-sm"
</button>
{{-- HANYA PENGURUS YANG BISA VALIDASI STATUS PENDING --}}
@if ($userRole == 'Pengurus')
{{-- @if ($userRole == 'Pengurus')
<form action="{{ route('spp.bayar', $spp->id) }}" method="POST"
class="d-inline">
@csrf
<button type="submit"
class="btn btn-sm btn-success px-2 shadow-sm"
style="border-radius: 8px;"
onclick="return confirm('Validasi bukti transfer dan nyatakan LUNAS?')">
<i class="fas fa-check"></i> Validasi
</button>
</form>
@endif --}}
@if (in_array('Pengurus', $userRoles))
<form action="{{ route('spp.bayar', $spp->id) }}" method="POST"
class="d-inline">
@csrf
@ -418,5 +445,27 @@ function konfirmasiGenerate() {
@endif
});
// Fungsi konfirmasi menggunakan SweetAlert2 untuk Bayar Tunai
function konfirmasiBayarTunai(id, namaAnggota) {
Swal.fire({
title: 'Konfirmasi Pembayaran?',
text: `Apakah Anda yakin ingin memproses pembayaran tunai untuk ${namaAnggota}?`,
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#0d6efd',
cancelButtonColor: '#6c757d',
confirmButtonText: '<i class="fas fa-check me-1"></i> Ya, Proses!',
cancelButtonText: 'Batal',
reverseButtons: true
}).then((result) => {
if (result.isConfirmed) {
// Submit form spesifik berdasarkan ID
document.getElementById('formBayarTunai-' + id).submit();
}
});
}
</script>
@endsection