multi role + kolat

This commit is contained in:
ell 2026-06-08 12:16:32 +07:00
parent e748c8cb60
commit 54a4a3a44b
37 changed files with 983 additions and 296 deletions

View File

@ -13,7 +13,7 @@ class AnggotaExport implements FromCollection, WithHeadings, WithMapping, Should
public function collection()
{
// Ambil data Anggota dengan relasi kolat dan user (untuk email)
return Anggota::whereHas('role', function($query) {
return Anggota::whereHas('roles', function($query) {
$query->where('nama_role', 'Anggota');
})->with(['kolat', 'user'])->get();
}

View File

@ -18,11 +18,12 @@ class AnggotaController extends Controller
{
// 1. Menampilkan Daftar Anggota
public function anggota()
{
// Filter data: Ambil anggota yang relasi 'role'-nya bernama 'Anggota'
$data_anggota = Anggota::whereHas('role', function($query) {
$data_anggota = Anggota::whereHas('roles', function($query) {
$query->where('nama_role', 'Anggota');
})->with(['kolat', 'role'])
})->with(['kolat', 'roles'])
->latest()
->get();
@ -61,12 +62,11 @@ public function store(Request $request)
$user = User::create([
'email' => $request->email,
'password' => Hash::make('tapakmp123'), // Password default
'role_id' => $request->role_id,
]);
// B. Cari nama jabatan berdasarkan role
$role = Role::find($request->role_id);
$nama_jabatan = strtolower($role->nama_role);
$nama_jabatan = $role ? strtolower($role->nama_role) : 'anggota';
// C. Logika No Induk (JB-001)
$terakhir = Anggota::orderBy('id', 'desc')->first();
@ -74,11 +74,10 @@ public function store(Request $request)
$no_induk_baru = "JB-" . $nomor_urut;
// D. Simpan Profil di tabel Anggotas
Anggota::create([
$anggota = Anggota::create([
'user_id' => $user->id,
'no_induk' => $no_induk_baru,
'nama_lengkap' => $request->nama_lengkap,
'role_id' => $request->role_id,
'jenis_kelamin' => $request->jenis_kelamin,
'tempat_lahir' => $request->tempat_lahir,
'tgl_lahir' => $request->tgl_lahir,
@ -92,6 +91,8 @@ public function store(Request $request)
'status' => 'Aktif', // Input admin otomatis aktif
]);
$anggota->roles()->attach($request->role_id);
DB::commit();
return redirect()->route('anggota.anggota')
->with('success', 'Data berhasil ditambah! Password login: tapakmp123');
@ -106,7 +107,7 @@ public function store(Request $request)
// 4. Menampilkan Form Edit
public function edit($id)
{
$anggota = Anggota::with('user')->findOrFail($id);
$anggota = Anggota::with(['user', 'roles'])->findOrFail($id);
$data_kolat = Kolat::all(); // Ambil daftar kolat lagi untuk pilihan saat edit
$data_role = Role::all();
@ -134,18 +135,19 @@ public function update(Request $request, $id)
// A. Update tabel User (email & role)
$user->update([
'email' => $request->email,
'role_id' => $request->role_id
]);
// B. Update jabatan berdasarkan role baru
$role = Role::find($request->role_id);
$nama_jabatan = strtolower($role->nama_role);
$nama_jabatan = $role ? strtolower($role->nama_role) : 'anggota';
// C. Update tabel Anggota
$data_anggota = $request->all();
// $data_anggota = $request->all();
$data_anggota = $request->except(['email', 'role_id', '_token', '_method']);
$data_anggota['jabatan'] = $nama_jabatan;
$anggota->update($data_anggota);
$anggota->roles()->sync([$request->role_id]);
DB::commit();
return redirect()->route('anggota.anggota')
@ -166,7 +168,7 @@ public function exportExcel()
public function exportPdf()
{
$data_anggota = Anggota::whereHas('role', function($query) {
$data_anggota = Anggota::whereHas('roles', function($query) {
$query->where('nama_role', 'Anggota');
})->with(['kolat', 'user'])->get();

View File

@ -44,13 +44,32 @@ public function login(Request $request)
$request->session()->regenerate();
// 2. Ambil Nama Role (samakan logikanya dengan Middleware)
// $roleName = null;
// if ($user->role) {
// $roleName = $user->role->nama_role;
// } elseif ($user->anggota && $user->anggota->role) {
// $roleName = $user->anggota->role->nama_role;
// }
$roleName = null;
if ($user->role) {
$roleName = $user->role->nama_role;
} elseif ($user->anggota && $user->anggota->role) {
$roleName = $user->anggota->role->nama_role;
$anggota = $user->anggota;
if ($anggota) {
// Cek apakah dia punya role Pengurus
if ($anggota->roles->contains('nama_role', 'Pengurus')) {
$roleName = 'Pengurus';
}
// Kalau bukan Pengurus, cek apakah dia Pelatih
elseif ($anggota->roles->contains('nama_role', 'Pelatih')) {
$roleName = 'Pelatih';
}
// Kalau bukan keduanya, berarti Anggota biasa
elseif ($anggota->roles->contains('nama_role', 'Anggota')) {
$roleName = 'Anggota';
}
}
// 3. Logika Pengarahan (Redirect) berdasarkan String Role
if ($roleName === 'Anggota') {
return redirect()->route('anggota.dashboard')->with('success', 'Selamat datang, Anggota!');
@ -110,7 +129,7 @@ public function register(Request $request)
$user = User::create([
'email' => $request->email,
'password' => Hash::make($request->password),
'role_id' => $role_id,
// 'role_id' => $role_id,
]);
// 3. Logika Penomoran Induk JB-xxx
@ -119,11 +138,11 @@ public function register(Request $request)
$no_induk_baru = "JB-" . $nomor_urut;
// 4. Buat Profil Anggota
Anggota::create([
$anggota =Anggota::create([
'user_id' => $user->id,
'no_induk' => $no_induk_baru,
'nama_lengkap' => $request->nama_lengkap,
'role_id' => $role_id,
// 'role_id' => $role_id,
'jenis_kelamin' => $request->jenis_kelamin,
'tempat_lahir' => $request->tempat_lahir,
'tgl_lahir' => $request->tgl_lahir,
@ -137,6 +156,8 @@ public function register(Request $request)
'status' => 'Non-Aktif', // Default sesuai permintaanmu
]);
$anggota->roles()->attach($role_id);
DB::commit();
return redirect()->route('login')->with('success', 'Registrasi Berhasil! Akun Anda akan segera diverifikasi oleh Admin.');

View File

@ -20,17 +20,21 @@ public function index()
// // Menghitung jumlah Kolat yang terdaftar
$total_kolat = Kolat::count();
$roleAnggota = Role::where('nama_role', 'Anggota')->first();
$rolePelatih = Role::where('nama_role', 'Pelatih')->first();
// $roleAnggota = Role::where('nama_role', 'Anggota')->first();
// $rolePelatih = Role::where('nama_role', 'Pelatih')->first();
// 2. Hitung jumlah "Anggota" (Hanya yang ber-role 'Anggota' DAN berstatus 'Aktif')
$total_anggota_aktif = Anggota::where('status', 'Aktif')
->where('role_id', $roleAnggota->id)
->whereHas('roles', function($q) {
$q->where('nama_role', 'Anggota');
})
->count();
// 3. Hitung jumlah "Pelatih" (Hanya yang ber-role 'Pelatih' DAN berstatus 'Aktif')
$total_pelatih = Anggota::where('status', 'Aktif')
->where('role_id', $rolePelatih->id)
->whereHas('roles', function($q) {
$q->where('nama_role', 'Pelatih');
})
->count();
// Menghitung SPP yang belum lunas (Pending atau Belum Lunas)

View File

@ -55,7 +55,7 @@ public function create()
$data_kolat = Kolat::all();
// Ambil Anggota yang memiliki role 'Pelatih' dan statusnya 'Aktif'
$data_pelatih = Anggota::whereHas('role', function($query) {
$data_pelatih = Anggota::whereHas('roles', function($query) {
$query->where('nama_role', 'Pelatih');
})
->where('status', 'Aktif')
@ -98,7 +98,7 @@ public function edit($id)
$data_kolat = Kolat::all();
// Tetap filter agar hanya muncul daftar pelatih
$data_pelatih = Anggota::whereHas('role', function($query) {
$data_pelatih = Anggota::whereHas('roles', function($query) {
$query->where('nama_role', 'Pelatih');
})->get();

View File

@ -55,9 +55,22 @@ public function update(Request $request, $id)
}
// 4. Hapus Data Kolat
// public function destroy($id)
// {
// $kolat = Kolat::findOrFail($id);
// $kolat->delete();
// return redirect()->back()->with('success', 'Kolat telah dihapus!');
// }
public function destroy($id)
{
$kolat = Kolat::findOrFail($id);
// Cek apakah ada anggota di kolat ini
if ($kolat->anggota()->count() > 0) {
return redirect()->back()->with('error', 'Kolat tidak bisa dihapus karena masih ada anggota yang terdaftar di dalamnya!');
}
$kolat->delete();
return redirect()->back()->with('success', 'Kolat telah dihapus!');
}

View File

@ -75,4 +75,4 @@ public function index()
return view('anggota.dashboard', compact('anggota', 'jadwal', 'tagihan_spp', 'persentase_hadir'));
}
};
}

View File

@ -14,9 +14,10 @@ class PelatihController extends Controller
public function index()
{
// Asumsi: Role pelatih memiliki nama 'Pelatih' di tabel roles
$data_pelatih = Anggota::whereHas('role', function($q) {
$data_pelatih = Anggota::whereHas('roles', function($q) {
$q->where('nama_role', 'Pelatih');
})->with('kolat')->get();
})->with('kolatLatihan')->get();
// })->with('kolat')->get();
return view('pelatih.pelatih', compact('data_pelatih'));
}
@ -25,11 +26,15 @@ public function index()
public function create()
{
// Ambil anggota yang role-nya masih 'Anggota' (bukan pelatih)
$calon_pelatih = Anggota::whereHas('role', function($q) {
$calon_pelatih = Anggota::whereHas('roles', function($q) {
$q->where('nama_role', 'Anggota');
})->whereDoesntHave('roles', function($q) {
$q->where('nama_role', 'Pelatih');
})->get();
return view('pelatih.pelatihcreate', compact('calon_pelatih'));
$data_kolat = Kolat::all();
return view('pelatih.pelatihcreate', compact('calon_pelatih', 'data_kolat'));
}
// Proses Upgrade Anggota ke Pelatih
@ -41,6 +46,8 @@ public function store(Request $request)
'tgl_sk' => 'required|date',
'masa_berlaku' => 'required|date',
'foto_sk' => 'nullable|image|mimes:jpg,png,jpeg|max:2048',
'kolat_ids' => 'required|array',
'kolat_ids.*' => 'exists:kolat,id',
]);
// Cari data anggota berdasarkan ID yang dipilih
@ -51,20 +58,30 @@ public function store(Request $request)
// Data yang akan diupdate
$updateData = [
'role_id' => $rolePelatih->id,
'jabatan' => 'pelatih', // Update status jabatan
// 'role_id' => $rolePelatih->id,
// 'jabatan' => 'pelatih', // Update status jabatan
'no_sk' => $request->no_sk,
'tgl_sk' => $request->tgl_sk,
'masa_berlaku' => $request->masa_berlaku,
'status' => 'Aktif',
];
$jabatan_lama = strtolower($anggota->jabatan);
if (empty($jabatan_lama) || $jabatan_lama == 'anggota') {
$updateData['jabatan'] = 'Pelatih'; // Jika kosong/anggota biasa, set murni Pelatih
} else if (!str_contains($jabatan_lama, 'pelatih')) {
$updateData['jabatan'] = $anggota->jabatan . ', Pelatih'; // Gabungkan, misal: "Sekretaris, Pelatih"
}
// Handle upload foto SK jika ada
if ($request->hasFile('foto_sk')) {
$path = $request->file('foto_sk')->store('sk_pelatih', 'public');
$updateData['foto_sk'] = $path;
}
$anggota->roles()->syncWithoutDetaching([$rolePelatih->id]);
$anggota->kolatLatihan()->sync($request->kolat_ids);
// Eksekusi Update
$anggota->update($updateData);
@ -93,9 +110,12 @@ public function update(Request $request, $id)
'no_sk' => 'required|unique:anggotas,no_sk,' . $id, // pastikan nama tabel benar 'anggota'
'tgl_sk' => 'nullable|date', // tambahkan jika di form ada tgl_sk
'foto_sk' => 'nullable|image|max:2048',
'kolat_ids' => 'required|array',
'kolat_ids.*' => 'exists:kolat,id',
]);
$data = $request->all();
// $data = $request->all();
$data = $request->except(['kolat_ids', '_token', '_method']);
if ($request->hasFile('foto_sk')) {
if ($pelatih->foto_sk) {
@ -105,6 +125,7 @@ public function update(Request $request, $id)
}
$pelatih->update($data);
$pelatih->kolatLatihan()->sync($request->kolat_ids);
return redirect()->route('pelatih.index')->with('success', 'Data kepelatihan diperbarui!');
}

View File

@ -0,0 +1,112 @@
<?php
namespace App\Http\Controllers;
use App\Models\Anggota;
use App\Models\Role;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class PengurusController extends Controller
{
// Menampilkan Daftar Pengurus Cabang
public function index()
{
$data_pengurus = Anggota::whereHas('roles', function($q) {
$q->where('nama_role', 'Pengurus');
})->latest()->get();
return view('pengurus.index', compact('data_pengurus'));
}
// Menampilkan Form Angkat Pengurus Baru
public function create()
{
// Aturan: Harus sudah memiliki role Pelatih, tetapi BELUM memiliki role Pengurus
$calon_pengurus = Anggota::whereHas('roles', function($q) {
$q->where('nama_role', 'Pelatih');
})->whereDoesntHave('roles', function($q) {
$q->where('nama_role', 'Pengurus');
})->get();
return view('pengurus.create', compact('calon_pengurus'));
}
// Menyimpan Data Pengurus Baru ke Database
public function store(Request $request)
{
$request->validate([
'anggota_id' => 'required|exists:anggotas,id',
'jabatan_struktural' => 'required|string|max:255', // Contoh: Ketua, Sekretaris, Bendahara
]);
DB::beginTransaction();
try {
$anggota = Anggota::findOrFail($request->anggota_id);
$rolePengurus = Role::where('nama_role', 'Pengurus')->firstOrFail();
// Gabungkan jabatan lama (pelatih) dengan jabatan struktural baru
$jabatan_baru = $anggota->jabatan . ', Pengurus (' . $request->jabatan_struktural . ')';
// 1. Tambahkan role Pengurus ke tabel pivot tanpa menghapus role lama
$anggota->roles()->syncWithoutDetaching([$rolePengurus->id]);
// 2. Perbarui kolom jabatan strukturalnya
$anggota->update([
'jabatan' => $jabatan_baru
]);
DB::commit();
return redirect()->route('pengurus.index')
->with('success', $anggota->nama_lengkap . ' berhasil diangkat menjadi Pengurus!');
} catch (\Exception $e) {
DB::rollBack();
Log::error("Gagal mengangkat pengurus: " . $e->getMessage());
return back()->withInput()->with('error', 'Terjadi kesalahan sistem saat memproses data.');
}
}
// Menampilkan Form Edit Jabatan Struktural Pengurus
public function edit($id)
{
$pengurus = Anggota::whereHas('roles', function($q) {
$q->where('nama_role', 'Pengurus');
})->findOrFail($id);
// Ekstrak nilai di dalam kurung dari string jabatan untuk mempermudah edit di form
// Contoh: "Pelatih, Pengurus (Sekretaris)" diambil kata "Sekretaris"
preg_match('#\((.*?)\)#', $pengurus->jabatan, $match);
$jabatan_sekarang = $match[1] ?? '';
return view('pengurus.edit', compact('pengurus', 'jabatan_sekarang'));
}
// Membarui Jabatan Struktural Pengurus
public function update(Request $request, $id)
{
$request->validate([
'jabatan_struktural' => 'required|string|max:255',
]);
try {
$pengurus = Anggota::findOrFail($id);
// Set ulang string jabatannya dengan nilai struktural yang baru
$jabatan_baru = 'Pelatih, Pengurus (' . $request->jabatan_struktural . ')';
$pengurus->update([
'jabatan' => $jabatan_baru
]);
return redirect()->route('pengurus.index')
->with('success', 'Jabatan struktural ' . $pengurus->nama_lengkap . ' berhasil diperbarui!');
} catch (\Exception $e) {
Log::error("Gagal update jabatan pengurus: " . $e->getMessage());
return back()->with('error', 'Terjadi kesalahan sistem saat memperbarui data.');
}
}
}

View File

@ -14,7 +14,7 @@ class PenilaianController extends Controller
public function index()
{
// Mencari anggota berdasarkan relasi 'role' yang bernama 'Pelatih'
$data_pelatih = Anggota::whereHas('role', function ($query) {
$data_pelatih = Anggota::whereHas('roles', function ($query) {
$query->where('nama_role', 'Pelatih');
})
->with('kolat')
@ -151,7 +151,7 @@ public function exportPdf($id)
public function indexAnggota()
{
// Ubah juga bagian ini menggunakan whereHas
$data_pelatih = Anggota::whereHas('role', function ($query) {
$data_pelatih = Anggota::whereHas('roles', function ($query) {
$query->where('nama_role', 'Pelatih');
})
->with('kolat')

View File

@ -14,7 +14,8 @@ public function index(Request $request) // Tambahkan Request untuk filter
$data_kolat = Kolat::all();
// 2. Query data anggota dengan filter
$query = Anggota::with(['presensi', 'spp', 'kolat']);
// $query = Anggota::with(['presensi', 'spp', 'kolat']);
$query = Anggota::with(['presensi', 'spp', 'kolatLatihan']);
if ($request->kolat_id) {
$query->where('kolat_id', $request->kolat_id);
@ -46,7 +47,8 @@ public function index(Request $request) // Tambahkan Request untuk filter
'nama' => $item->nama_lengkap, // Sesuaikan dengan kolom tabel Anda
'no_induk' => $item->no_induk,
'tingkatan' => $item->tingkatan,
'nama_kolat' => $item->kolat->nama_kolat ?? '-',
// 'nama_kolat' => $item->kolat->nama_kolat ?? '-',
'nama_kolat' => $item->kolatLatihan->pluck('nama_kolat')->join(', '),
'status_aktif' => $statusAktif,
'persentase_presensi' => round($persentasePresensi, 1),
'status_spp' => $punyaTunggakan ? 'Ada Tunggakan' : 'Lunas',

View File

@ -16,32 +16,55 @@ class CheckRole
*/
public function handle(Request $request, Closure $next, ...$roles): Response
{
// // 1. Pastikan user sudah login
// if (!Auth::check()) {
// return redirect()->route('login');
// }
// $user = Auth::user();
// $namaRole = null;
// // 2. Ambil nama_role dari relasi.
// if ($user->role) {
// $namaRole = $user->role->nama_role;
// } elseif ($user->anggota && $user->anggota->role) {
// $namaRole = $user->anggota->role->nama_role;
// }
// // ==========================================
// // LETAKKAN KODE DD DI SINI (UNTUK DEBUGGING)
// // ==========================================
// // dd('Role di DB: ' . $namaRole, 'Role di Rute: ', $roles);
// // 3. Cek apakah nama_role user ada di dalam daftar role
// if (in_array($namaRole, $roles)) {
// return $next($request);
// }
// // 4. Jika role tidak cocok, tolak akses
// abort(403, 'Akses Ditolak. Anda tidak memiliki wewenang untuk mengakses halaman ini.');
// baru
// 1. Pastikan user sudah login
if (!Auth::check()) {
return redirect()->route('login');
}
$user = Auth::user();
$namaRole = null;
// 2. Ambil nama_role dari relasi.
if ($user->role) {
$namaRole = $user->role->nama_role;
} elseif ($user->anggota && $user->anggota->role) {
$namaRole = $user->anggota->role->nama_role;
// 2. LOGIKA BARU: Pengecekan Banyak Peran (Multiple Roles)
if ($user->anggota) {
// Looping daftar role yang diizinkan oleh Route (misal: 'Pengurus', 'Pelatih')
foreach ($roles as $role) {
// Jika user yang sedang login punya salah satu role tersebut, langsung loloskan!
if ($user->anggota->roles->contains('nama_role', $role)) {
return $next($request);
}
}
}
// ==========================================
// LETAKKAN KODE DD DI SINI (UNTUK DEBUGGING)
// ==========================================
// dd('Role di DB: ' . $namaRole, 'Role di Rute: ', $roles);
// 3. Cek apakah nama_role user ada di dalam daftar role
if (in_array($namaRole, $roles)) {
return $next($request);
}
// 4. Jika role tidak cocok, tolak akses
// 3. Jika tidak ada satupun role yang cocok, tolak akses
abort(403, 'Akses Ditolak. Anda tidak memiliki wewenang untuk mengakses halaman ini.');
}
}

View File

@ -13,7 +13,7 @@ class Anggota extends Model
protected $table = 'anggotas';
protected $fillable = [
'user_id', 'no_induk', 'nama_lengkap', 'foto_profil', 'role_id', 'jenis_kelamin',
'user_id', 'no_induk', 'nama_lengkap', 'foto_profil', 'jenis_kelamin',
'tempat_lahir', 'tgl_lahir', 'no_hp', 'kolat_id',
'tingkatan', 'tgl_gabung', 'status', 'alamat',
'catatan_medis', 'jabatan', 'no_sk', 'masa_berlaku', 'foto_sk'
@ -25,20 +25,46 @@ public function kolat()
return $this->belongsTo(Kolat::class, 'kolat_id');
}
public function role()
// public function role()
// {
// return $this->belongsTo(Role::class, 'role_id');
// }
// TAMBAHKAN relasi baru ini:
public function roles()
{
return $this->belongsTo(Role::class, 'role_id');
// Menghubungkan Anggota ke Role lewat tabel pivot anggota_role
return $this->belongsToMany(Role::class, 'anggota_role', 'anggota_id', 'role_id')->withTimestamps();
}
/**
* Fungsi bantuan (Helper) untuk mengecek apakah anggota memiliki role tertentu.
* Sangat berguna nanti di Controller, Middleware, atau Blade.
*/
public function hasRole($roleName)
{
return $this->roles()->where('nama_role', $roleName)->exists();
}
public function kolatLatihan()
{
return $this->belongsToMany(Kolat::class, 'kolat_pelatih', 'anggota_id', 'kolat_id');
}
// Scope agar gampang memanggil data yang hanya ber-role Pelatih
// public function scopeIsPelatih($query)
// {
// return $query->whereHas('role', function ($q) {
// $q->where('nama_role', 'Pelatih');
// });
// }
// KODE BARU (Ubah jadi 'roles')
public function scopeIsPelatih($query)
{
return $query->whereHas('role', function ($q) {
return $query->whereHas('roles', function ($q) { // <-- Ubah 'role' jadi 'roles'
$q->where('nama_role', 'Pelatih');
});
}

View File

@ -26,8 +26,6 @@ public function anggota()
public function pelatihs()
{
// Panggil relasi pivot, lalu sambungkan dengan scope isPelatih()
return $this->belongsToMany(Anggota::class, 'kolat_pelatih', 'kolat_id', 'anggota_id')
->isPelatih();
return $this->belongsToMany(Anggota::class, 'kolat_pelatih', 'kolat_id', 'anggota_id')->withTimestamps();
}
}

View File

@ -11,4 +11,9 @@ class Role extends Model
protected $table = 'role'; // Pastikan nama tabelnya 'roles' di database
protected $fillable = ['nama_role']; // Sesuaikan kolom di tabel roles kamu
public function anggotas()
{
return $this->belongsToMany(Anggota::class, 'anggota_role', 'role_id', 'anggota_id')->withTimestamps();
}
}

View File

@ -18,7 +18,6 @@ class User extends Authenticatable
* @var array<int, string>
*/
protected $fillable = [
'role_id',
'email',
'password',
];

View File

@ -29,7 +29,14 @@ public function boot(): void
View::composer('*', function ($view) {
if (Auth::check()) {
$user = Auth::user();
$userRole = $user->role->nama_role; // Sesuaikan dengan cara Anda ambil role
$userRole = 'Anggota';
if ($user->anggota) {
if ($user->anggota->roles->contains('nama_role', 'Pengurus')) {
$userRole = 'Pengurus';
} elseif ($user->anggota->roles->contains('nama_role', 'Pelatih')) {
$userRole = 'Pelatih';
}
}// Sesuaikan dengan cara Anda ambil role
$notifications = [];
$unreadCount = 0;

View File

@ -14,7 +14,7 @@ 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('role_id')->constrained('role')->onDelete('cascade');
$table->foreignId('kolat_id')->constrained('kolat')->onDelete('cascade');
// --- DATA IDENTITAS ---

View File

@ -12,7 +12,7 @@
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->foreignId('role_id')->after('id')->constrained('role')->onDelete('cascade');
// $table->foreignId('role_id')->after('id')->constrained('role')->onDelete('cascade');
});
}
@ -22,8 +22,8 @@ public function up(): void
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropForeign(['role_id']);
$table->dropColumn('role_id');
// $table->dropForeign(['role_id']);
// $table->dropColumn('role_id');
});
}
};

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('anggota_role', function (Blueprint $table) {
$table->id();
// Relasi ke tabel anggotas
$table->foreignId('anggota_id')->constrained('anggotas')->onDelete('cascade');
// Relasi ke tabel roles (asumsi nama tabel master role kamu adalah 'roles')
$table->foreignId('role_id')->constrained('role')->onDelete('cascade');
$table->timestamps();
// Kunci unik agar satu orang tidak bisa punya role yang sama persis secara ganda
$table->unique(['anggota_id', 'role_id']);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('anggota_role');
}
};

View File

@ -13,7 +13,7 @@ class DatabaseSeeder extends Seeder
public function run(): void
{
$this->call([
RoleSeeder::class,
RoleSeeder::class,
KolatSeeder::class,
UserSeeder::class,
]);

View File

@ -16,32 +16,43 @@ 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();
// 2. Buat Akun User untuk Pelatih
$user = User::create([
'role_id' => $rolePelatih->id,
'email' => 'pelatih@tapakmp.com',
'password' => Hash::make('password123'), // Password default
]);
// 3. Buat Profil Anggota untuk User tersebut
Anggota::create([
$anggota = Anggota::create([
'user_id' => $user->id,
'role_id' => $rolePelatih->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, // Pastikan sudah ada data Kolat ID 1 atau sesuaikan
'kolat_id' => 1, // Menyambung ke Kolat Unej di KolatSeeder
'tingkatan' => 'Balik 1',
'tgl_gabung' => now(),
'status' => 'Aktif',
'alamat' => 'Jl. Merpati Putih No. 1, Jember',
'jabatan' => 'Pelatih Kolat',
'jabatan' => 'Pelatih, Pengurus Kolat',
]);
// 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)
if ($rolePengurus) {
$anggota->roles()->attach($rolePengurus->id);
}
}
}

View File

@ -164,10 +164,25 @@ class="fw-bold text-primary mb-3 border-bottom pb-2">
<span
class="fw-bold text-dark">{{ $item->kolat->nama_kolat ?? '-' }}</span>
</div>
<div class="col-6">
{{-- <div class="col-6">
<small class="text-muted d-block">Jabatan</small>
<span
class="fw-bold text-primary text-uppercase">{{ $item->role->nama_role ?? 'ANGGOTA' }}</span>
</div> --}}
<div class="col-6">
<small class="text-muted d-block">Jabatan
Terdaftar</small>
<div class="d-flex flex-wrap gap-1 mt-1">
@forelse($item->roles as $role)
<span
class="badge bg-primary text-white text-uppercase"
style="font-size: 10px;">{{ $role->nama_role }}</span>
@empty
<span
class="badge bg-secondary text-white text-uppercase"
style="font-size: 10px;">ANGGOTA</span>
@endforelse
</div>
</div>
<div class="col-6">
<small class="text-muted d-block">Tingkatan</small>
@ -303,11 +318,11 @@ class="icon-heart me-2"></i>Catatan
.btn-action-edit {
background-color: #fff8e6;
color: #f59e0b;
border: 1px solid #ffecb3;
border-radius: 10px;
transition: 0.3s;
}
color: #f59e0b;
border: 1px solid #ffecb3;
border-radius: 10px;
transition: 0.3s;
}
.btn-action-edit:hover {
background-color: #f59e0b !important;

View File

@ -2,8 +2,17 @@
@section('content')
@php
// Ambil nama role user yang login saat ini
$userRole = auth()->user()->role->nama_role ?? 'Anggota';
// LOGIKA BARU: Ambil nama role user menggunakan relasi pivot
$user = auth()->user();
$userRole = 'Anggota';
if ($user && $user->anggota) {
if ($user->anggota->roles->contains('nama_role', 'Pengurus')) {
$userRole = 'Pengurus';
} elseif ($user->anggota->roles->contains('nama_role', 'Pelatih')) {
$userRole = 'Pelatih';
}
}
@endphp
<div class="container-fluid py-4">
@ -120,7 +129,7 @@
@endif
<option value="{{ $role->id }}"
{{ old('role_id', $anggota->role_id ?? '') == $role->id ? 'selected' : '' }}>
{{ old('role_id', (isset($anggota) && $anggota->roles->contains('id', $role->id)) ? $role->id : '') == $role->id ? 'selected' : '' }}>
{{ $role->nama_role }}
</option>
@endforeach
@ -209,7 +218,7 @@ function toggleSKFields() {
const roleSelect = document.getElementById('roleSelect');
const boxSK = document.getElementById('boxSK');
if (boxSK && roleSelect.selectedIndex > 0) {
const selectedText = roleSelect.options[roleSelect.selectedIndex].text.toLowerCase();

View File

@ -1,206 +1,251 @@
@extends('layout.app')
@section('content')
@php
// Ambil nama role user yang login saat ini
$userRole = auth()->user()->role->nama_role ?? 'Anggota';
@endphp
@php
// LOGIKA BARU: Ambil nama role user menggunakan relasi pivot
$user = auth()->user();
$userRole = 'Anggota';
<div class="container-fluid py-4">
@if ($errors->any())
<div class="alert alert-danger border-0 shadow-sm mb-4" style="border-radius: 15px;">
<div class="d-flex">
<i class="icon-alert-circle me-2 mt-1"></i>
<ul class="mb-0">
@foreach ($errors->all() as $error)
<li class="small">{{ $error }}</li>
@endforeach
</ul>
if ($user && $user->anggota) {
if ($user->anggota->roles->contains('nama_role', 'Pengurus')) {
$userRole = 'Pengurus';
} elseif ($user->anggota->roles->contains('nama_role', 'Pelatih')) {
$userRole = 'Pelatih';
}
}
@endphp
<div class="container-fluid py-4">
@if ($errors->any())
<div class="alert alert-danger border-0 shadow-sm mb-4" style="border-radius: 15px;">
<div class="d-flex">
<i class="icon-alert-circle me-2 mt-1"></i>
<ul class="mb-0">
@foreach ($errors->all() as $error)
<li class="small">{{ $error }}</li>
@endforeach
</ul>
</div>
</div>
@endif
<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="{{ route('anggota.anggota') }}"
class="text-muted text-decoration-none small">Daftar Anggota</a></li>
<li class="breadcrumb-item active text-primary fw-bold small" aria-current="page">Edit Anggota</li>
</ol>
</nav>
<h3 class="fw-bold text-dark">Form Edit Anggota Merpati Putih</h3>
</div>
<div class="row">
<div class="col-md-12">
<form action="{{ route('anggota.update', $anggota->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<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 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">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 login
sistem</small>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Role / Hak Akses</label>
<select name="role_id" class="form-select" required>
@foreach ($data_role as $role)
{{-- LOGIKA PENGAMANAN ROLE --}}
@if ($userRole != 'Pengurus' && strtolower($role->nama_role) != 'anggota')
@continue
@endif
<option value="{{ $role->id }}"
{{ $anggota->roles->contains('id', $role->id) ? 'selected' : '' }}>
{{ $role->nama_role }}
</option>
@endforeach
</select>
</div>
<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>
</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">No. WhatsApp</label>
<div class="input-group">
<input type="number" name="no_hp" class="form-control"
value="{{ old('no_hp', $anggota->no_hp) }}" required>
</div>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Alamat</label>
<input type="text" name="alamat" class="form-control"
value="{{ old('alamat', $anggota->alamat) }}" required>
</div>
</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-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 Khusus</label>
<select name="jabatan" id="jabatanSelect" class="form-select border-primary"
onchange="toggleSKFields()" required>
<option value="anggota"
{{ !$anggota->roles->contains('nama_role', 'Pelatih') && !$anggota->roles->contains('nama_role', 'Pengurus') ? 'selected' : '' }}>
Anggota</option>
{{-- HANYA PENGURUS YANG BISA JADIKAN PELATIH/PENGURUS --}}
@if ($userRole == 'Pengurus')
<option value="pelatih"
{{ $anggota->roles->contains('nama_role', 'Pelatih') ? 'selected' : '' }}>
Pelatih</option>
<option value="pengurus"
{{ $anggota->roles->contains('nama_role', 'Pengurus') ? 'selected' : '' }}>
Pengurus</option>
@endif
</select>
@if ($userRole != 'Pengurus')
<small class="text-info mt-1 d-block"><i class="icon-info me-1"></i>Anda hanya dapat
mengubah data Anggota biasa.</small>
@endif
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Tingkatan</label>
<input type="text" name="tingkatan" class="form-control"
value="{{ old('tingkatan', $anggota->tingkatan) }}" required>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Status</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 SK HANYA DIBUKA UNTUK PENGURUS --}}
@if ($userRole == '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">Data Legalitas SK</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 }}">
</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 (Gambar)</label>
<input type="file" name="foto_sk" class="form-control">
</div>
</div>
</div>
@endif
<div class="col-md-12 mt-3">
<label class="form-label fw-bold">Asal Kolat</label>
<select name="kolat_id" class="form-select" required>
@foreach ($data_kolat as $kolat)
<option value="{{ $kolat->id }}"
{{ $anggota->kolat_id == $kolat->id ? 'selected' : '' }}>
{{ $kolat->nama_kolat }}
</option>
@endforeach
</select>
</div>
</div>
</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 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>
</form>
</div>
</div>
@endif
<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="{{ route('anggota.anggota') }}" class="text-muted text-decoration-none small">Daftar Anggota</a></li>
<li class="breadcrumb-item active text-primary fw-bold small" aria-current="page">Edit Anggota</li>
</ol>
</nav>
<h3 class="fw-bold text-dark">Form Edit Anggota Merpati Putih</h3>
</div>
<div class="row">
<div class="col-md-12">
<form action="{{ route('anggota.update', $anggota->id) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<script>
function toggleSKFields() {
const jabatanSelect = document.getElementById('jabatanSelect');
const boxSK = document.getElementById('boxSK');
<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 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">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 login sistem</small>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Role / Hak Akses</label>
<select name="role_id" class="form-select" required>
@foreach($data_role as $role)
{{-- LOGIKA PENGAMANAN ROLE --}}
@if($userRole != 'Pengurus' && strtolower($role->nama_role) != 'anggota')
@continue
@endif
<option value="{{ $role->id }}" {{ $anggota->role_id == $role->id ? 'selected' : '' }}>
{{ $role->nama_role }}
</option>
@endforeach
</select>
</div>
<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>
</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">No. WhatsApp</label>
<div class="input-group">
<input type="number" name="no_hp" class="form-control" value="{{ old('no_hp', $anggota->no_hp) }}" required>
</div>
</div>
<div class="col-md-6">
<label class="form-label fw-bold">Alamat</label>
<input type="text" name="alamat" class="form-control" value="{{ old('alamat', $anggota->alamat) }}" required>
</div>
</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-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 Khusus</label>
<select name="jabatan" id="jabatanSelect" class="form-select border-primary" onchange="toggleSKFields()" required>
<option value="anggota" {{ $anggota->jabatan == 'anggota' ? 'selected' : '' }}>Anggota</option>
{{-- HANYA PENGURUS YANG BISA JADIKAN PELATIH/PENGURUS --}}
@if($userRole == 'Pengurus')
<option value="pelatih" {{ $anggota->jabatan == 'pelatih' ? 'selected' : '' }}>Pelatih</option>
<option value="pengurus" {{ $anggota->jabatan == 'pengurus' ? 'selected' : '' }}>Pengurus</option>
@endif
</select>
@if($userRole != 'Pengurus')
<small class="text-info mt-1 d-block"><i class="icon-info me-1"></i>Anda hanya dapat mengubah data Anggota biasa.</small>
@endif
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Tingkatan</label>
<input type="text" name="tingkatan" class="form-control" value="{{ old('tingkatan', $anggota->tingkatan) }}" required>
</div>
<div class="col-md-4">
<label class="form-label fw-bold">Status</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 SK HANYA DIBUKA UNTUK PENGURUS --}}
@if($userRole == '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">Data Legalitas SK</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 }}">
</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 (Gambar)</label>
<input type="file" name="foto_sk" class="form-control">
</div>
</div>
</div>
@endif
<div class="col-md-12 mt-3">
<label class="form-label fw-bold">Asal Kolat</label>
<select name="kolat_id" class="form-select" required>
@foreach ($data_kolat as $kolat)
<option value="{{ $kolat->id }}" {{ $anggota->kolat_id == $kolat->id ? 'selected' : '' }}>
{{ $kolat->nama_kolat }}
</option>
@endforeach
</select>
</div>
</div>
</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 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>
</form>
</div>
</div>
</div>
<script>
function toggleSKFields() {
const jabatanSelect = document.getElementById('jabatanSelect');
const boxSK = document.getElementById('boxSK');
if (boxSK && jabatanSelect) {
const jabatan = jabatanSelect.value;
boxSK.style.display = (jabatan === 'pelatih' || jabatan === 'pengurus') ? 'block' : 'none';
if (boxSK && jabatanSelect) {
const jabatan = jabatanSelect.value;
boxSK.style.display = (jabatan === 'pelatih' || jabatan === 'pengurus') ? 'block' : 'none';
}
}
}
document.addEventListener("DOMContentLoaded", toggleSKFields);
</script>
document.addEventListener("DOMContentLoaded", toggleSKFields);
</script>
<style>
.form-control, .form-select {
border-radius: 10px;
padding: 10px 15px;
border: 1px solid #dce1e7;
}
.form-control:focus, .form-select:focus {
border-color: #0d6efd;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.1);
}
.btn-save {
border-radius: 12px;
background: linear-gradient(45deg, #0d6efd, #004dc0);
border: none;
color: white;
}
.btn-cancel {
border-radius: 12px;
}
.bg-light { background-color: #f8f9fa !important; }
</style>
<style>
.form-control,
.form-select {
border-radius: 10px;
padding: 10px 15px;
border: 1px solid #dce1e7;
}
.form-control:focus,
.form-select:focus {
border-color: #0d6efd;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.1);
}
.btn-save {
border-radius: 12px;
background: linear-gradient(45deg, #0d6efd, #004dc0);
border: none;
color: white;
}
.btn-cancel {
border-radius: 12px;
}
.bg-light {
background-color: #f8f9fa !important;
}
</style>
@endsection

View File

@ -1,6 +1,30 @@
@extends('layout.app')
@section('content')
@php
// LOGIKA MULTI-ROLE: Memeriksa jabatan apa saja yang tersemat pada pengguna ini
$user = auth()->user();
// Periksa apakah user memiliki tabel anggota yang terhubung
$isPengurus = false;
$isPelatih = false;
if ($user && $user->anggota) {
$isPengurus = $user->anggota->roles->contains('nama_role', 'Pengurus');
$isPelatih = $user->anggota->roles->contains('nama_role', 'Pelatih');
}
// Tentukan label yang akan tampil di header
if ($isPengurus && $isPelatih) {
$roleDisplay = 'Pengurus & Pelatih';
} elseif ($isPengurus) {
$roleDisplay = 'Pengurus Cabang';
} elseif ($isPelatih) {
$roleDisplay = 'Pelatih Kolat';
} else {
$roleDisplay = 'Anggota Biasa';
}
@endphp
<div class="container-fluid py-4">
<!-- Header Section -->
<div class="row align-items-center mb-4">
@ -19,7 +43,7 @@
</div>
<div class="text-start me-3">
<small class="text-muted d-block" style="font-size: 10px;">ROLE AKSES</small>
<span class="fw-bold small text-primary">Administrator</span>
<span class="fw-bold small text-primary">{{ $roleDisplay }}</span>
</div>
</div>
</div>

View File

@ -1,12 +1,14 @@
@php
// Ambil nama role user dengan logika yang sama persis seperti di Middleware
// LOGIKA BARU: Deteksi multi-role dari tabel perantara (pivot) roles()
$user = auth()->user();
$userRole = null;
$userRole = 'Anggota'; // Default fallback
if ($user->role) {
$userRole = $user->role->nama_role;
} elseif ($user->anggota && $user->anggota->role) {
$userRole = $user->anggota->role->nama_role;
if ($user && $user->anggota) {
if ($user->anggota->roles->contains('nama_role', 'Pengurus')) {
$userRole = 'Pengurus';
} elseif ($user->anggota->roles->contains('nama_role', 'Pelatih')) {
$userRole = 'Pelatih';
}
}
@endphp
@ -21,7 +23,7 @@
<!-- Link khusus untuk Anggota -->
<a class="nav-link {{ request()->routeIs('anggota.dashboard') ? '' : 'collapsed' }}" href="{{ route('anggota.dashboard') }}">
<i class="bi bi-grid"></i>
<span>Dashboard</span>
<span>Dashboard</span>
</a>
@else
<!-- Link untuk Pelatih dan Pengurus -->

View File

@ -82,7 +82,7 @@ class="text-muted text-decoration-none small">Daftar Pelatih</a></li>
<input type="text" name="tingkatan" class="form-control"
value="{{ old('tingkatan', $pelatih->tingkatan) }}" required>
</div>
<div class="col-md-8">
{{-- <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)
@ -91,6 +91,24 @@ class="text-muted text-decoration-none small">Daftar Pelatih</a></li>
</option>
@endforeach
</select>
</div> --}}
<div class="col-md-8">
<label class="form-label fw-bold">Kolat Binaan (Tempat Melatih)</label>
{{-- Ambil data ID Kolat yang sudah pernah dipilih pelatih ini --}}
@php
$selectedKolat = old('kolat_ids', $pelatih->kolatLatihan->pluck('id')->toArray());
@endphp
<select name="kolat_ids[]" class="form-control select2 shadow-none" multiple="multiple" style="border-radius: 12px;" required>
@foreach ($data_kolat as $kolat)
{{-- Gunakan in_array untuk menandai kolat mana saja yang sudah ditugaskan ke dia --}}
<option value="{{ $kolat->id }}" {{ in_array($kolat->id, $selectedKolat) ? 'selected' : '' }}>
{{ $kolat->nama_kolat }}
</option>
@endforeach
</select>
<small class="text-muted">Bisa memilih lebih dari satu kolat sekaligus.</small>
</div>
<div class="col-12 mt-3 p-4 bg-light rounded-4 border border-dashed border-danger">
@ -143,4 +161,18 @@ class="text-muted text-decoration-none small">Daftar Pelatih</a></li>
.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>
@push('scripts')
<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...",
width: '100%'
});
});
</script>
@endpush
@endsection

View File

@ -1,9 +1,14 @@
@extends('layout.app')
@section('content')
@php
{{-- @php
// Ambil nama role user yang login saat ini
$userRole = auth()->user()->role->nama_role ?? 'Anggota';
@endphp --}}
@php
// LOGIKA BARU: Cek apakah user yang login punya role 'Pengurus' di tabel pivot
$user = auth()->user();
$isPengurus = $user->anggota && $user->anggota->roles->contains('nama_role', 'Pengurus');
@endphp
<div class="container-fluid py-4">
@ -29,7 +34,7 @@
</div>
<!-- HANYA PENGURUS YANG BISA MELIHAT TOMBOL INI -->
@if($userRole == 'Pengurus')
@if($isPengurus)
<a href="{{ route('pelatih.upgrade') }}" class="btn btn-primary px-4 py-2 shadow-sm"
style="border-radius: 12px;">
<i class="icon-plus me-1"></i> Upgrade Anggota ke Pelatih
@ -48,7 +53,7 @@
<th>Status SK</th>
<!-- KOLOM AKSI HANYA MUNCUL JIKA PENGURUS -->
@if($userRole == 'Pengurus')
@if($isPengurus)
<th>Aksi</th>
@endif
</tr>
@ -65,8 +70,19 @@
<div class="small fw-bold">{{ $item->no_sk }}</div>
<div class="text-muted" style="font-size: 11px;">Hingga: {{ \Carbon\Carbon::parse($item->masa_berlaku)->format('d M Y') }}</div>
</td>
<td class="text-center">
{{-- <td class="text-center">
<span class="badge bg-info-soft text-info px-3">{{ $item->kolat->nama_kolat ?? '-' }}</span>
</td> --}}
<td class="text-center">
@if($item->kolatLatihan->count() > 0)
@foreach($item->kolatLatihan as $kolat)
<span class="badge bg-info-soft text-info px-3 mb-1 d-inline-block">
{{ $kolat->nama_kolat }}
</span>
@endforeach
@else
<span class="text-muted small">- Belum ada kolat -</span>
@endif
</td>
<td class="text-center">
@php
@ -78,12 +94,12 @@
</td>
<!-- TOMBOL EDIT HANYA MUNCUL JIKA PENGURUS -->
@if($userRole == 'Pengurus')
@if($isPengurus)
<td class="text-center">
<div class="d-flex justify-content-center gap-2">
<a href="{{ route('pelatih.edit', $item->id) }}"
class="btn btn-sm btn-action-edit fw-bold px-2 shadow-xs">
<i class="bi bi-pencil"></i>
<i class="bi bi-pencil"></i>
</a>
</div>
</td>

View File

@ -26,6 +26,16 @@
<small class="text-muted">Hanya anggota yang belum memiliki jabatan pelatih yang muncul di sini.</small>
</div>
<div class="mb-4">
<label class="form-label fw-bold text-dark">Tugaskan ke Kolat (Tempat Melatih)</label>
<select name="kolat_ids[]" class="form-control select2 shadow-none" multiple="multiple" style="border-radius: 12px;" required>
@foreach($data_kolat as $kolat)
<option value="{{ $kolat->id }}">{{ $kolat->nama_kolat }}</option>
@endforeach
</select>
<small class="text-muted">Bisa memilih lebih dari satu kolat sekaligus.</small>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-bold text-dark">Nomor SK Pelatih</label>
@ -76,7 +86,10 @@
<script>
$(document).ready(function() {
$('.select2').select2({
theme: 'bootstrap-5'
theme: 'bootstrap-5',
placeholder: "Klik untuk memilih Kolat...",
allowClear: true,
width: '100%' // Memastikan dropdown memenuhi lebar kolom
});
});
</script>

View File

@ -0,0 +1,65 @@
@extends('layout.app')
@section('content')
<div class="container-fluid py-4">
<div class="page-header mb-4">
<h3 class="fw-bold text-dark">Angkat Pengurus Struktural</h3>
<p class="text-muted">Proses ini memberikan wewenang administratif tingkat cabang kepada Pelatih terpilih.</p>
</div>
<div class="row">
<div class="col-md-8">
<div class="card border-0 shadow-sm" style="border-radius: 20px;">
<div class="card-body p-4">
<form action="{{ route('pengurus.store') }}" method="POST">
@csrf
<div class="mb-4">
<label class="form-label fw-bold text-dark">Pilih Pelatih (Calon Pengurus)</label>
<select name="anggota_id" class="form-control select2 shadow-none" style="border-radius: 12px;" required>
<option value="">-- Cari Nama Pelatih Berdasarkan No Induk --</option>
@foreach($calon_pengurus as $item)
<option value="{{ $item->id }}">{{ $item->no_induk }} - {{ $item->nama_lengkap }} ({{ $item->tingkatan }})</option>
@endforeach
</select>
<small class="text-muted">Sesuai aturan hierarki, hanya fungsionaris bertatus Pelatih yang dapat diangkat ke kepengurusan struktural.</small>
</div>
<div class="mb-4">
<label class="form-label fw-bold text-dark">Jabatan Struktural Cabang</label>
<input type="text" name="jabatan_struktural" class="form-control shadow-none" placeholder="Contoh: Ketua Cabang, Sekretaris, Bendahara" style="border-radius: 10px;" required>
<small class="text-muted">Tuliskan nama posisi spesifik yang akan diemban di kepengurusan.</small>
</div>
<div class="d-flex gap-2 pt-2">
<button type="submit" class="btn btn-primary px-5 shadow-sm" style="border-radius: 12px;">Simpan & Tetapkan</button>
<a href="{{ route('pengurus.index') }}" class="btn btn-light px-4" style="border-radius: 12px;">Batal</a>
</div>
</form>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-0 bg-primary text-white p-2 shadow-sm" style="border-radius: 20px;">
<div class="card-body">
<h5 class="fw-bold mb-3"><i class="bi bi-info-circle me-2"></i>Sistem Multi-Role</h5>
<ul class="small opacity-9 text-white ps-3">
<li class="mb-2">Akses kepelatihan lapangan yang bersangkutan tidak akan hilang atau terhapus.</li>
<li class="mb-2">Sistem secara otomatis akan menggabungkan peran lama dengan posisi struktural baru di riwayat jabatan.</li>
<li>Pengurus baru akan langsung diberikan hak penuh untuk mengelola data anggota keseluruhan serta laporan keuangan tingkat cabang.</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function() {
$('.select2').select2({
theme: 'bootstrap-5'
});
});
</script>
@endsection

View File

@ -0,0 +1,60 @@
@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="{{ route('pengurus.index') }}" class="text-muted text-decoration-none small">Daftar Pengurus</a></li>
<li class="breadcrumb-item active text-primary fw-bold small" aria-current="page">Edit Jabatan</li>
</ol>
</nav>
<h3 class="fw-bold text-dark">Ubah Jabatan Struktural</h3>
<p class="text-muted small">Perbarui data fungsionaris struktural pengurus atas nama <strong>{{ $pengurus->nama_lengkap }}</strong>.</p>
</div>
<div class="row">
<div class="col-md-8">
<form action="{{ route('pengurus.update', $pengurus->id) }}" method="POST">
@csrf
@method('PUT')
<div class="card border-0 shadow-sm mb-4" style="border-radius: 20px;">
<div class="card-body p-4">
<div class="mb-3">
<label class="form-label fw-bold">Nama Lengkap</label>
<input type="text" class="form-control bg-light" value="{{ $pengurus->nama_lengkap }}" readonly>
</div>
<div class="mb-3">
<label class="form-label fw-bold">Nomor Induk Anggota</label>
<input type="text" class="form-control bg-light" value="{{ $pengurus->no_induk }}" readonly>
</div>
<div class="mb-4">
<label class="form-label fw-bold">Posisi Struktural Baru</label>
<input type="text" name="jabatan_struktural" class="form-control" value="{{ old('jabatan_struktural', $jabatan_sekarang) }}" required placeholder="Contoh: Ketua Cabang, Bendahara I">
<small class="text-muted">*Perubahan posisi ini tidak akan mengganggu data riwayat kepelatihan yang bersangkutan.</small>
</div>
<div class="d-flex justify-content-start gap-3">
<button type="submit" class="btn btn-primary px-5 fw-bold btn-save shadow">Simpan Perubahan</button>
<a href="{{ route('pengurus.index') }}" class="btn btn-outline-secondary px-4 fw-bold btn-cancel">Batal</a>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<style>
.form-control { 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); }
.btn-cancel { border-radius: 12px; transition: all 0.3s ease; border: 2px solid #6c757d; color: #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; color: white;}
.btn-save:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(79, 70, 229, 0.4) !important; color: white;}
</style>
@endsection

View File

@ -0,0 +1,102 @@
@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">Manajemen Pengurus</li>
</ol>
</nav>
<h3 class="fw-bold text-dark">Struktural Pengurus Cabang</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">Daftar Pengurus Aktif</h5>
<p class="text-muted small mb-0">Kelola fungsionaris struktural dan kepengurusan organisasi.</p>
</div>
<a href="{{ route('pengurus.create') }}" class="btn btn-primary px-4 py-2 shadow-sm" style="border-radius: 12px;">
<i class="bi bi-shield-plus me-1"></i> Angkat Pengurus Baru
</a>
</div>
@if(session('success'))
<div class="alert alert-success alert-dismissible fade show border-0 mb-3 shadow-sm" style="border-radius: 10px;">
{{ 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>
<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>
</tr>
</thead>
<tbody>
@forelse ($data_pengurus 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>{{ $item->no_hp }}</td>
<td>
<div class="fw-bold text-primary mb-1">{{ ucwords($item->jabatan) }}</div>
@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>
</td>
<td class="text-center">
<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">
<i class="bi bi-pencil"></i>
</a>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="6" class="text-muted py-4">Belum ada anggota yang diangkat menjadi pengurus struktural.</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-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); }
.shadow-xs { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); }
</style>
@endsection

View File

@ -56,8 +56,15 @@
Hingga: {{ $item->masa_berlaku ? \Carbon\Carbon::parse($item->masa_berlaku)->format('d M Y') : '-' }}
</div>
</td>
<td class="text-center">
{{-- <td class="text-center">
<span class="badge bg-info-soft text-info px-3">{{ $item->kolat->nama_kolat ?? '-' }}</span>
</td> --}}
<td class="text-center">
@forelse($item->kolatLatihan as $kolat)
<span class="badge bg-info-soft text-info px-2 mb-1 d-block">{{ $kolat->nama_kolat }}</span>
@empty
<span class="text-muted small">-</span>
@endforelse
</td>
<td class="text-center">
@php

View File

@ -40,7 +40,13 @@
</tr>
<tr>
<td class="label">Unit Latihan</td>
<td>: Kolat {{ $pelatih->kolat->nama_kolat ?? '-' }}</td>
{{-- <td>: Kolat {{ $pelatih->kolat->nama_kolat ?? '-' }}</td> --}}
<td class="label">Unit Latihan</td>
<td>:
@foreach($pelatih->kolatLatihan as $kolat)
{{ $kolat->nama_kolat }}{{ !$loop->last ? ', ' : '' }}
@endforeach
</td>
<td class="label">Tanggal Cetak</td>
<td>: {{ now()->format('d/m/Y') }}</td>
</tr>

View File

@ -409,7 +409,7 @@
<div class="mb-3">
<label class="form-label fw-bold">Jabatan</label>
<div class="p-2 bg-light rounded text-dark fw-semibold border border-light">
{{ $anggota->role->nama_role }}
{{ $anggota->roles->pluck('nama_role')->join(', ') }}
</div>
</div>
<div class="mb-3">

View File

@ -9,6 +9,7 @@
use App\Http\Controllers\LaporanController;
use App\Http\Controllers\MemberDashboardController;
use App\Http\Controllers\PelatihController;
use App\Http\Controllers\PengurusController;
use App\Http\Controllers\PenilaianController;
use App\Http\Controllers\PresensiController;
use App\Http\Controllers\ProfileController;
@ -131,7 +132,7 @@
Route::middleware('checkrole:Pengurus')->group(function () {
// Aksi CRUD Anggota
Route::get('/anggota/export/excel ', [AnggotaController::class, 'exportExcel'])->name('anggota.export.excel');
Route::get('/anggota/export/excel', [AnggotaController::class, 'exportExcel'])->name('anggota.export.excel');
Route::get('/anggota/export/pdf', [AnggotaController::class, 'exportPdf'])->name('anggota.export.pdf');
// Aksi CRUD Kolat
@ -185,4 +186,13 @@
});
Route::middleware(['auth', 'checkrole:Pengurus'])->group(function () {
Route::get('/pengurus', [PengurusController::class, 'index'])->name('pengurus.index');
Route::get('/pengurus/create', [PengurusController::class, 'create'])->name('pengurus.create');
Route::post('/pengurus/store', [PengurusController::class, 'store'])->name('pengurus.store');
Route::get('/pengurus/{id}/edit', [PengurusController::class, 'edit'])->name('pengurus.edit');
Route::put('/pengurus/{id}/update', [PengurusController::class, 'update'])->name('pengurus.update');
});