diff --git a/app/Enums/Bumdes/JabatanBumdes.php b/app/Enums/Bumdes/JabatanBumdes.php new file mode 100644 index 0000000..8500f4d --- /dev/null +++ b/app/Enums/Bumdes/JabatanBumdes.php @@ -0,0 +1,46 @@ + 'Direktur/Ketua', + self::DIREKTUR_KETUA => 'Direktur/Ketua', + self::SEKRETARIS => 'Sekretaris', + self::BENDAHARA => 'Bendahara', + self::KEPALA_UNIT_USAHA => 'Kepala Unit Usaha', + self::PENGAWAS => 'Pengawas', + self::PENASIHAT => 'Penasihat', + self::ANGGOTA => 'Anggota', + self::STAF_OPERASIONAL => 'Staf Operasional', + self::LAINNYA => 'Lainnya', + }; + } + + public static function options(): array + { + return collect([ + self::DIREKTUR_KETUA, + self::SEKRETARIS, + self::BENDAHARA, + self::LAINNYA, + ])->map(fn ($case) => [ + 'value' => $case->value, + 'label' => $case->label(), + ])->toArray(); + } +} diff --git a/app/Http/Controllers/Web/Bumdes/PengurusBumdesController.php b/app/Http/Controllers/Web/Bumdes/PengurusBumdesController.php new file mode 100644 index 0000000..93ec50b --- /dev/null +++ b/app/Http/Controllers/Web/Bumdes/PengurusBumdesController.php @@ -0,0 +1,218 @@ +orderBy('created_at', 'desc'); + + if ($request->search) { + $query->where(function ($query) use ($request) { + $query->where('nama', 'like', '%' . $request->search . '%') + ->orWhere('jabatan', 'like', '%' . $request->search . '%') + ->orWhere('jabatan_lainnya', 'like', '%' . $request->search . '%'); + }); + } + + if (auth()->user()->role->value === 'fasilitator') { + $query->where('created_by', auth()->id()); + } + + $summaryQuery = clone $query; + $totalPengurus = (clone $summaryQuery)->count(); + $totalLakiLaki = (clone $summaryQuery)->where('jenis_kelamin', true)->count(); + $totalPerempuan = (clone $summaryQuery)->where('jenis_kelamin', false)->count(); + $totalDesaKelurahan = (clone $summaryQuery)->distinct('desa_kelurahan_id')->count('desa_kelurahan_id'); + $totalJabatan = (clone $summaryQuery)->distinct('jabatan')->count('jabatan'); + + $pengurus = $query->paginate($request->per_page ?? 10); + $userRole = auth()->user()->role->value; + $showEnumerator = in_array($userRole, ['super_admin', 'admin']); + + return view('bumdes.profil.index', compact( + 'pengurus', + 'totalPengurus', + 'totalLakiLaki', + 'totalPerempuan', + 'totalDesaKelurahan', + 'totalJabatan', + 'showEnumerator' + )); + } + + public function create() + { + if (! Gate::any(['super_admin', 'admin', 'fasilitator'])) { + abort(403); + } + + $provinsi = Provinsi::select('id', 'kode', 'nama')->orderBy('kode', 'asc')->get(); + $jabatan = JabatanBumdes::options(); + $pendidikan = Pendidikan::options(); + + return view('bumdes.profil.add', compact('provinsi', 'jabatan', 'pendidikan')); + } + + public function store(Request $request) + { + if (! Gate::any(['super_admin', 'admin', 'fasilitator'])) { + abort(403); + } + + $validatedData = $this->validatedData($request); + + $pengurus = PengurusBumdes::create([ + ...$this->formatData($validatedData), + 'uid' => 'BMD-' . strtoupper(Str::random(10)), + 'created_by' => auth()->id(), + 'updated_by' => auth()->id(), + ]); + + return redirect()->route('bumdes.edit', $pengurus->id)->with('success', 'Data pengurus BUMDes berhasil ditambahkan.'); + } + + public function show(string $id) + { + return redirect()->route('bumdes.edit', $id); + } + + public function edit(string $id) + { + if (! Gate::any(['super_admin', 'admin', 'fasilitator'])) { + abort(403); + } + + $pengurus = $this->pengurusQuery()->with([ + 'desaKelurahan.kecamatan.kabupatenKota.provinsi', + ])->findOrFail($id); + $provinsi = Provinsi::select('id', 'kode', 'nama')->orderBy('kode', 'asc')->get(); + $jabatan = JabatanBumdes::options(); + $pendidikan = Pendidikan::options(); + + return view('bumdes.profil.edit', compact('pengurus', 'provinsi', 'jabatan', 'pendidikan')); + } + + public function update(Request $request, string $id) + { + if (! Gate::any(['super_admin', 'admin', 'fasilitator'])) { + abort(403); + } + + $pengurus = $this->pengurusQuery()->findOrFail($id); + $validatedData = $this->validatedData($request); + + $pengurus->update([ + ...$this->formatData($validatedData), + 'updated_by' => auth()->id(), + ]); + + return redirect()->route('bumdes.edit', $pengurus->id)->with('success', 'Data pengurus BUMDes berhasil diupdate.'); + } + + public function destroy(string $id) + { + if (! Gate::any(['super_admin', 'admin', 'fasilitator'])) { + abort(403); + } + + $pengurus = $this->pengurusQuery()->findOrFail($id); + $pengurus->update(['deleted_by' => auth()->id()]); + $pengurus->delete(); + + return response()->json(['message' => 'Data pengurus BUMDes berhasil dihapus.']); + } + + public function kelembagaanAktor(string $id) + { + if (! Gate::any(['super_admin', 'admin', 'fasilitator'])) { + abort(403); + } + + $pengurus = $this->pengurusQuery()->with([ + 'desaKelurahan.kecamatan.kabupatenKota.provinsi', + ])->findOrFail($id); + + return view('bumdes.kelembagaan-aktor.index', compact('pengurus')); + } + + private function pengurusQuery() + { + $query = PengurusBumdes::query(); + + if (auth()->user()->role->value === 'fasilitator') { + $query->where('created_by', auth()->id()); + } + + return $query; + } + + private function validatedData(Request $request): array + { + return $request->validate([ + 'nama' => ['required', 'string', 'max:255'], + 'jenis_kelamin' => ['required', 'boolean'], + 'tempat_lahir' => ['required', 'string', 'max:255'], + 'tanggal_lahir' => ['required', 'date_format:d-m-Y'], + 'pendidikan_terakhir' => ['required', Rule::enum(Pendidikan::class)], + 'alamat' => ['required', 'string', 'max:500'], + 'desa_kelurahan_id' => ['required', 'exists:master_desa_kelurahan,id'], + 'nomor_telepon' => ['nullable', 'digits_between:11,13'], + 'jabatan' => ['required', Rule::enum(JabatanBumdes::class)], + 'jabatan_lainnya' => ['nullable', 'required_if:jabatan,' . JabatanBumdes::LAINNYA->value, 'string', 'max:255'], + 'lama_menjabat_tahun' => ['required', 'integer', 'min:0', 'max:80'], + ], [ + 'nama.required' => 'Nama harus diisi.', + 'jenis_kelamin.required' => 'Jenis kelamin harus dipilih.', + 'tempat_lahir.required' => 'Tempat lahir harus diisi.', + 'tanggal_lahir.required' => 'Tanggal lahir harus diisi.', + 'tanggal_lahir.date_format' => 'Tanggal lahir harus menggunakan format tanggal yang valid.', + 'pendidikan_terakhir.required' => 'Pendidikan terakhir harus dipilih.', + 'alamat.required' => 'Alamat harus diisi.', + 'desa_kelurahan_id.required' => 'Desa kelurahan harus dipilih.', + 'desa_kelurahan_id.exists' => 'Desa kelurahan tidak ditemukan.', + 'nomor_telepon.digits_between' => 'Nomor telepon harus berupa angka 11 sampai 13 digit.', + 'jabatan.required' => 'Jabatan/peran harus dipilih.', + 'jabatan_lainnya.required_if' => 'Jabatan lainnya harus diisi.', + 'lama_menjabat_tahun.required' => 'Lama menjabat harus diisi.', + 'lama_menjabat_tahun.integer' => 'Lama menjabat harus berupa angka tahun.', + ]); + } + + private function formatData(array $data): array + { + $data['tanggal_lahir'] = Carbon::createFromFormat('d-m-Y', $data['tanggal_lahir'])->format('Y-m-d'); + $data['tanggal_mulai_menjabat'] = Carbon::now() + ->subYears((int) $data['lama_menjabat_tahun']) + ->format('Y-m-d'); + + if (($data['jabatan'] ?? null) !== JabatanBumdes::LAINNYA->value) { + $data['jabatan_lainnya'] = null; + } + + return $data; + } +} diff --git a/app/Models/Bumdes/PengurusBumdes.php b/app/Models/Bumdes/PengurusBumdes.php new file mode 100644 index 0000000..b91b49a --- /dev/null +++ b/app/Models/Bumdes/PengurusBumdes.php @@ -0,0 +1,108 @@ + 'boolean', + 'tanggal_lahir' => 'date', + 'pendidikan_terakhir' => Pendidikan::class, + 'tanggal_mulai_menjabat' => 'date', + 'jabatan' => JabatanBumdes::class, + ]; + + public function getUsiaAttribute(): ?int + { + if (! $this->tanggal_lahir) { + return null; + } + + return Carbon::parse($this->tanggal_lahir)->age; + } + + public function getLamaMenjabatAttribute(): string + { + if (! is_null($this->lama_menjabat_tahun)) { + return $this->lama_menjabat_tahun . ' tahun'; + } + + if (! $this->tanggal_mulai_menjabat) { + return '-'; + } + + $tanggalMulai = Carbon::parse($this->tanggal_mulai_menjabat)->startOfDay(); + + if ($tanggalMulai->isFuture()) { + return 'Belum mulai'; + } + + $selisih = $tanggalMulai->diff(Carbon::now()); + $bagian = []; + + if ($selisih->y > 0) { + $bagian[] = $selisih->y . ' tahun'; + } + + if ($selisih->m > 0) { + $bagian[] = $selisih->m . ' bulan'; + } + + if (empty($bagian)) { + return $selisih->d . ' hari'; + } + + return implode(' ', $bagian); + } + + public function getNamaJabatanAttribute(): string + { + if ($this->jabatan === JabatanBumdes::LAINNYA && $this->jabatan_lainnya) { + return $this->jabatan_lainnya; + } + + return $this->jabatan?->label() ?? '-'; + } + + public function desaKelurahan(): BelongsTo + { + return $this->belongsTo(DesaKelurahan::class, 'desa_kelurahan_id'); + } + + public function creator(): BelongsTo + { + return $this->belongsTo(User::class, 'created_by'); + } +} diff --git a/database/migrations/2026_07_28_140000_create_bumdes_pengurus_table.php b/database/migrations/2026_07_28_140000_create_bumdes_pengurus_table.php new file mode 100644 index 0000000..f9c758c --- /dev/null +++ b/database/migrations/2026_07_28_140000_create_bumdes_pengurus_table.php @@ -0,0 +1,38 @@ +id(); + $table->string('uid')->unique(); + $table->string('nama'); + $table->boolean('jenis_kelamin'); + $table->string('tempat_lahir')->nullable(); + $table->date('tanggal_lahir'); + $table->string('pendidikan_terakhir')->nullable(); + $table->text('alamat')->nullable(); + $table->foreignId('desa_kelurahan_id')->nullable()->constrained('master_desa_kelurahan')->onDelete('set null'); + $table->string('nomor_telepon')->nullable(); + $table->string('jabatan'); + $table->string('jabatan_lainnya')->nullable(); + $table->unsignedSmallInteger('lama_menjabat_tahun')->nullable(); + $table->date('tanggal_mulai_menjabat'); + $table->foreignId('created_by')->nullable()->constrained('users')->onDelete('set null'); + $table->foreignId('updated_by')->nullable()->constrained('users')->onDelete('set null'); + $table->foreignId('deleted_by')->nullable()->constrained('users')->onDelete('set null'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + public function down(): void + { + Schema::dropIfExists('bumdes_pengurus'); + } +}; diff --git a/database/migrations/2026_07_28_150000_add_profile_fields_to_bumdes_pengurus_table.php b/database/migrations/2026_07_28_150000_add_profile_fields_to_bumdes_pengurus_table.php new file mode 100644 index 0000000..78731f4 --- /dev/null +++ b/database/migrations/2026_07_28_150000_add_profile_fields_to_bumdes_pengurus_table.php @@ -0,0 +1,42 @@ +string('pendidikan_terakhir')->nullable()->after('tanggal_lahir'); + } + + if (! Schema::hasColumn('bumdes_pengurus', 'jabatan_lainnya')) { + $table->string('jabatan_lainnya')->nullable()->after('jabatan'); + } + + if (! Schema::hasColumn('bumdes_pengurus', 'lama_menjabat_tahun')) { + $table->unsignedSmallInteger('lama_menjabat_tahun')->nullable()->after('jabatan_lainnya'); + } + }); + } + + public function down(): void + { + Schema::table('bumdes_pengurus', function (Blueprint $table) { + if (Schema::hasColumn('bumdes_pengurus', 'lama_menjabat_tahun')) { + $table->dropColumn('lama_menjabat_tahun'); + } + + if (Schema::hasColumn('bumdes_pengurus', 'jabatan_lainnya')) { + $table->dropColumn('jabatan_lainnya'); + } + + if (Schema::hasColumn('bumdes_pengurus', 'pendidikan_terakhir')) { + $table->dropColumn('pendidikan_terakhir'); + } + }); + } +}; diff --git a/resources/views/bumdes/kelembagaan-aktor/index.blade.php b/resources/views/bumdes/kelembagaan-aktor/index.blade.php new file mode 100644 index 0000000..e3a0d75 --- /dev/null +++ b/resources/views/bumdes/kelembagaan-aktor/index.blade.php @@ -0,0 +1,7 @@ +@extends('layout.main') + +@section('content') +
+ @include('bumdes.profil.header', ['pengurus' => $pengurus]) +
+@endsection diff --git a/resources/views/bumdes/profil/_form.blade.php b/resources/views/bumdes/profil/_form.blade.php new file mode 100644 index 0000000..e3231b5 --- /dev/null +++ b/resources/views/bumdes/profil/_form.blade.php @@ -0,0 +1,280 @@ +@php + $prefix = $mode . '-bumdes'; + $currentProvinsiId = old('provinsi_id', $pengurus?->desaKelurahan?->kecamatan?->kabupatenKota?->provinsi_id); + $currentKabupaten = $pengurus?->desaKelurahan?->kecamatan?->kabupatenKota; + $currentKecamatan = $pengurus?->desaKelurahan?->kecamatan; + $currentDesa = $pengurus?->desaKelurahan; + $currentJabatan = $pengurus?->jabatan instanceof \App\Enums\Bumdes\JabatanBumdes ? $pengurus->jabatan->value : $pengurus?->jabatan; + $currentPendidikan = $pengurus?->pendidikan_terakhir instanceof \App\Enums\Pendidikan ? $pengurus->pendidikan_terakhir->value : $pengurus?->pendidikan_terakhir; +@endphp + +
Data Pribadi
+
+
+ + + @error('nama')
{{ $message }}
@enderror +
+
+ + + @error('jenis_kelamin')
{{ $message }}
@enderror +
+
+ + + @error('tempat_lahir')
{{ $message }}
@enderror +
+
+ + + @error('tanggal_lahir')
{{ $message }}
@enderror +
+
+
+
+ + + @error('pendidikan_terakhir')
{{ $message }}
@enderror +
+
+ +
Peran Kepengurusan BUMDes
+
+
+ + + @error('jabatan')
{{ $message }}
@enderror +
+
+ + + @error('jabatan_lainnya')
{{ $message }}
@enderror +
+
+ + + @error('lama_menjabat_tahun')
{{ $message }}
@enderror +
+
+ +
Domisili dan Kontak
+
+
+ + + @error('alamat')
{{ $message }}
@enderror +
+
+
+
+ + + @error('provinsi_id')
{{ $message }}
@enderror +
+
+ + + @error('kabupaten_id')
{{ $message }}
@enderror +
+
+ + + @error('kecamatan_id')
{{ $message }}
@enderror +
+
+ + + @error('desa_kelurahan_id')
{{ $message }}
@enderror +
+
+ +
+
+ + + @error('nomor_telepon')
{{ $message }}
@enderror +
+
+ +@push('scripts') + +@endpush diff --git a/resources/views/bumdes/profil/add.blade.php b/resources/views/bumdes/profil/add.blade.php new file mode 100644 index 0000000..740c812 --- /dev/null +++ b/resources/views/bumdes/profil/add.blade.php @@ -0,0 +1,34 @@ +@extends('layout.main') + +@section('content') +
+ @if ($errors->any()) +
+ +
+ @endif + + @include('bumdes.profil.header', ['pengurus' => null]) + +
+
+
Tambah Profil Pengurus BUMDes
+
+
+
+ @csrf + @include('bumdes.profil._form', ['pengurus' => null, 'mode' => 'add']) + +
+ Kembali + +
+
+
+
+
+@endsection diff --git a/resources/views/bumdes/profil/edit.blade.php b/resources/views/bumdes/profil/edit.blade.php new file mode 100644 index 0000000..bb27f75 --- /dev/null +++ b/resources/views/bumdes/profil/edit.blade.php @@ -0,0 +1,39 @@ +@extends('layout.main') + +@section('content') +
+ @if (session('success')) +
{{ session('success') }}
+ @endif + + @if ($errors->any()) +
+ +
+ @endif + + @include('bumdes.profil.header', ['pengurus' => $pengurus]) + +
+
+
Edit Profil Pengurus BUMDes
+
+
+
+ @csrf + @method('PUT') + @include('bumdes.profil._form', ['pengurus' => $pengurus, 'mode' => 'edit']) + +
+ Kembali + +
+
+
+
+
+@endsection diff --git a/resources/views/bumdes/profil/header.blade.php b/resources/views/bumdes/profil/header.blade.php new file mode 100644 index 0000000..64aee7f --- /dev/null +++ b/resources/views/bumdes/profil/header.blade.php @@ -0,0 +1,162 @@ + + +@php + $jenisKelamin = isset($pengurus) + ? ($pengurus->jenis_kelamin ? 'Laki-laki' : 'Perempuan') + : 'Jenis Kelamin'; + $jabatanLabel = isset($pengurus) ? $pengurus->nama_jabatan : 'Jabatan/Peran'; + $domisili = isset($pengurus) && $pengurus->desaKelurahan + ? $pengurus->desaKelurahan->nama . ', ' . $pengurus->desaKelurahan->kecamatan?->nama . ', ' . $pengurus->desaKelurahan->kecamatan?->kabupatenKota?->nama . ', ' . $pengurus->desaKelurahan->kecamatan?->kabupatenKota?->provinsi?->nama + : 'Desa/Kelurahan, Kecamatan, Kabupaten/Kota, Provinsi'; +@endphp + +
+
+
+
+
Profil Pengurus BUMDes
+
+
+ + + +
+
+
{{ isset($pengurus) ? $pengurus->nama : 'Tambah Pengurus BUMDes Baru' }}
+ {{ $jenisKelamin }} + Jabatan: {{ $jabatanLabel }} +
+
+ +
+
Domisili
+

Alamat: {{ isset($pengurus) ? $pengurus->alamat : 'Alamat' }}

+

{{ $domisili }}

+
+
+
+ +
+
+
+
+
+
+
+
+

Jenis Kelamin

+
{{ $jenisKelamin }}
+

+ {{ isset($pengurus) ? ($pengurus->usia . ' tahun') : 'Belum terisi' }} +

+
+ + + + + +
+
+
+
+
+

Jabatan

+
{{ $jabatanLabel }}
+

+ {{ isset($pengurus) ? $pengurus->lama_menjabat : 'Belum terisi' }} +

+
+ + + + + +
+
+
+
+
+

Domisili

+
{{ isset($pengurus) ? ($pengurus->desaKelurahan?->nama ?? '-') : '-' }}
+

+ {{ isset($pengurus) ? ($pengurus->desaKelurahan?->kecamatan?->nama ?? '-') : 'Belum terisi' }} +

+
+ + + + + +
+
+
+
+
+
+ +
+
+
+

Alamat Domisili

+
{{ isset($pengurus) ? ($pengurus->alamat ?: '-') : '-' }}
+

{{ $domisili }}

+
+
+
+
+
+ + diff --git a/resources/views/bumdes/profil/index.blade.php b/resources/views/bumdes/profil/index.blade.php new file mode 100644 index 0000000..97698c0 --- /dev/null +++ b/resources/views/bumdes/profil/index.blade.php @@ -0,0 +1,158 @@ +@extends('layout.main') + +@section('content') +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
Data Pengurus BUMDes
+
+ +
+
+
+
+ + + +
+
+
+
+ + +
+ + Tambah + +
+
+
+ +
+ + + + + + + + + + + @if($showEnumerator) + + @endif + + + + + @forelse($pengurus as $item) + + + + + + + + + @if($showEnumerator) + + @endif + + + @empty + + + + @endforelse + +
NoNamaJenis KelaminUsiaDesa/KelurahanJabatan/PeranLama MenjabatNama EnumeratorAksi
{{ ($pengurus->firstItem() ?? 0) + $loop->index }}{{ $item->nama }}{{ $item->jenis_kelamin ? 'Laki-laki' : 'Perempuan' }}{{ $item->usia }} tahun + + {{ $item->desaKelurahan?->nama }}, + {{ $item->desaKelurahan?->kecamatan?->nama }}, + {{ $item->desaKelurahan?->kecamatan?->kabupatenKota?->nama }}, + {{ $item->desaKelurahan?->kecamatan?->kabupatenKota?->provinsi?->nama }} + + {{ $item->nama_jabatan }}{{ $item->lama_menjabat }}{{ $item->creator?->name ?? '-' }} +
+ + +
+
Tidak ada data ditemukan.
+
+ +
+
+@endsection + +@push('scripts') + +@endpush diff --git a/resources/views/layout/sidebar.blade.php b/resources/views/layout/sidebar.blade.php index 13e4c03..4205194 100644 --- a/resources/views/layout/sidebar.blade.php +++ b/resources/views/layout/sidebar.blade.php @@ -64,6 +64,13 @@ + @endif @endif @@ -78,6 +85,15 @@
Profil Petani
+ + @endif @if(in_array($userRole, ['super_admin', 'admin']) && env('APP_NAME') == 'AgroPro') diff --git a/routes/web.php b/routes/web.php index c5683cb..806e4cd 100644 --- a/routes/web.php +++ b/routes/web.php @@ -45,6 +45,7 @@ Route::middleware('auth') // Dashboard Route::get('/dashboard/petani', [App\Http\Controllers\Web\Dashboard\ProfilPetaniController::class, 'index'])->name('dashboard.petani'); + Route::get('/dashboard/bumdes', [App\Http\Controllers\Web\Bumdes\PengurusBumdesController::class, 'index'])->name('dashboard.bumdes'); Route::get('/user-profile', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'index'])->name('userProfile.index'); @@ -223,4 +224,8 @@ Route::middleware('auth') Route::resource('petani.akses-pasar', App\Http\Controllers\Web\Produktivitas\AksesPasarController::class)->whereNumber('petani'); Route::resource('petani.skor', App\Http\Controllers\Web\Produktivitas\SkorPetaniController::class)->only(['index']); + + // BUMDes + Route::get('bumdes/{bumdes}/kelembagaan-aktor', [App\Http\Controllers\Web\Bumdes\PengurusBumdesController::class, 'kelembagaanAktor'])->name('bumdes.kelembagaan-aktor.index'); + Route::resource('bumdes', App\Http\Controllers\Web\Bumdes\PengurusBumdesController::class); });