6 Commits
18 changed files with 1298 additions and 43 deletions
+46
View File
@@ -0,0 +1,46 @@
<?php
namespace App\Enums\Bumdes;
enum JabatanBumdes: string
{
case DIREKTUR = 'direktur';
case DIREKTUR_KETUA = 'direktur_ketua';
case SEKRETARIS = 'sekretaris';
case BENDAHARA = 'bendahara';
case KEPALA_UNIT_USAHA = 'kepala_unit_usaha';
case PENGAWAS = 'pengawas';
case PENASIHAT = 'penasihat';
case ANGGOTA = 'anggota';
case STAF_OPERASIONAL = 'staf_operasional';
case LAINNYA = 'lainnya';
public function label(): string
{
return match ($this) {
self::DIREKTUR => '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();
}
}
@@ -0,0 +1,218 @@
<?php
namespace App\Http\Controllers\Web\Bumdes;
use App\Enums\Bumdes\JabatanBumdes;
use App\Enums\Pendidikan;
use App\Http\Controllers\Controller;
use App\Models\Bumdes\PengurusBumdes;
use App\Models\Wilayah\Provinsi;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
class PengurusBumdesController extends Controller
{
public function index(Request $request)
{
if (! Gate::any(['super_admin', 'admin', 'fasilitator'])) {
abort(403);
}
$query = PengurusBumdes::with([
'desaKelurahan:id,nama,kecamatan_id',
'desaKelurahan.kecamatan:id,nama,kabupaten_kota_id',
'desaKelurahan.kecamatan.kabupatenKota:id,nama,provinsi_id',
'desaKelurahan.kecamatan.kabupatenKota.provinsi:id,nama',
'creator:id,name',
])
->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;
}
}
@@ -34,12 +34,42 @@ class SummaryController extends Controller
$totalpetani = Profile::where('role', 'petani')->count();
$totallahan = Lahan::whereNotNull('path')->count();
$petaniList = Profile::where('role', 'petani')
->with(['lahan.tanaman.komoditas', 'desaKelurahan'])
$petaniList = Profile::select('id', 'nama', 'role', 'desa_kelurahan_id')
->where('role', 'petani')
->with([
'lahan:id,profile_id,luas_lahan',
'desaKelurahan:id,nama,kecamatan_id',
])
->paginate(20);
$allLahan = Lahan::whereNotNull('path')
->with(['profile', 'tanaman.komoditas', 'desaKelurahan.kecamatan.kabupatenKota.provinsi'])
$lahanSummaryByDesa = Lahan::whereNotNull('path')
->whereNotNull('desa_kelurahan_id')
->select('desa_kelurahan_id')
->selectRaw('COUNT(*) as total_lahan')
->selectRaw('COALESCE(SUM(luas_lahan), 0) as total_luas')
->groupBy('desa_kelurahan_id')
->get();
$desaList = DesaKelurahan::select('id', 'nama', 'path', 'kecamatan_id')
->whereIn('id', $lahanSummaryByDesa->pluck('desa_kelurahan_id')->filter()->unique()->values())
->with([
'kecamatan:id,nama,path,kabupaten_kota_id',
'kecamatan.kabupatenKota:id,nama,path,provinsi_id',
'kecamatan.kabupatenKota.provinsi:id,nama,path',
])
->get()
->keyBy('id');
$mapLahanLimit = min(max((int) $request->integer('map_lahan_limit', 500), 0), 2000);
$mapLahan = Lahan::whereNotNull('path')
->select('id', 'profile_id', 'desa_kelurahan_id', 'path', 'luas_lahan')
->with([
'profile:id,nama',
'tanaman:id,lahan_id,komoditas_id',
'tanaman.komoditas:id,nama',
])
->orderByDesc('updated_at')
->limit($mapLahanLimit)
->get();
$geoProvinsi = [];
@@ -48,47 +78,51 @@ class SummaryController extends Controller
$geoDesa = [];
$geoLahan = [];
foreach ($allLahan as $lahan) {
$desa = $lahan->desaKelurahan;
foreach ($lahanSummaryByDesa as $summary) {
$desa = $desaList->get($summary->desa_kelurahan_id);
$kec = $desa ? $desa->kecamatan : null;
$kab = $kec ? $kec->kabupatenKota : null;
$prov = $kab ? $kab->provinsi : null;
$totalLahan = (int) $summary->total_lahan;
$totalLuas = (float) $summary->total_luas;
if ($prov && $prov->path) {
if (!isset($geoProvinsi[$prov->id])) {
$geoProvinsi[$prov->id] = ['id' => $prov->id, 'nama' => $prov->nama, 'polygon' => $prov->path, 'total_lahan' => 0, 'total_luas' => 0];
}
$geoProvinsi[$prov->id]['total_lahan']++;
$geoProvinsi[$prov->id]['total_luas'] += $lahan->luas_lahan;
$geoProvinsi[$prov->id]['total_lahan'] += $totalLahan;
$geoProvinsi[$prov->id]['total_luas'] += $totalLuas;
}
if ($kab && $kab->path) {
if (!isset($geoKabupaten[$kab->id])) {
$geoKabupaten[$kab->id] = ['id' => $kab->id, 'parent_id' => $prov->id ?? null, 'nama' => $kab->nama, 'polygon' => $kab->path, 'total_lahan' => 0, 'total_luas' => 0];
}
$geoKabupaten[$kab->id]['total_lahan']++;
$geoKabupaten[$kab->id]['total_luas'] += $lahan->luas_lahan;
$geoKabupaten[$kab->id]['total_lahan'] += $totalLahan;
$geoKabupaten[$kab->id]['total_luas'] += $totalLuas;
}
if ($kec && $kec->path) {
if (!isset($geoKecamatan[$kec->id])) {
$geoKecamatan[$kec->id] = ['id' => $kec->id, 'parent_id' => $kab->id ?? null, 'nama' => $kec->nama, 'polygon' => $kec->path, 'total_lahan' => 0, 'total_luas' => 0];
}
$geoKecamatan[$kec->id]['total_lahan']++;
$geoKecamatan[$kec->id]['total_luas'] += $lahan->luas_lahan;
$geoKecamatan[$kec->id]['total_lahan'] += $totalLahan;
$geoKecamatan[$kec->id]['total_luas'] += $totalLuas;
}
if ($desa && $desa->path) {
if (!isset($geoDesa[$desa->id])) {
$geoDesa[$desa->id] = ['id' => $desa->id, 'parent_id' => $kec->id ?? null, 'nama' => $desa->nama, 'polygon' => $desa->path, 'total_lahan' => 0, 'total_luas' => 0];
}
$geoDesa[$desa->id]['total_lahan']++;
$geoDesa[$desa->id]['total_luas'] += $lahan->luas_lahan;
$geoDesa[$desa->id]['total_lahan'] += $totalLahan;
$geoDesa[$desa->id]['total_luas'] += $totalLuas;
}
}
foreach ($mapLahan as $lahan) {
$geoLahan[] = [
'id' => $lahan->id,
'parent_id' => $desa->id ?? null,
'parent_id' => $lahan->desa_kelurahan_id,
'polygon' => $lahan->path,
'nama_petani' => $lahan->profile->nama ?? 'N/A',
'luas' => $lahan->luas_lahan,
@@ -34,9 +34,16 @@ class PetaniController extends Controller
abort(403);
}
$provinsi = Provinsi::orderBy('kode', 'asc')->get();
$provinsi = Provinsi::select('id', 'kode', 'nama')->orderBy('kode', 'asc')->get();
$query = Petani::with('desakelurahan')
$query = Petani::with([
'desaKelurahan:id,nama,kecamatan_id',
'desaKelurahan.kecamatan:id,nama,kabupaten_kota_id',
'desaKelurahan.kecamatan.kabupatenKota:id,nama,provinsi_id',
'desaKelurahan.kecamatan.kabupatenKota.provinsi:id,nama',
'komoditas:id,nama',
'skor:id,petani_id,skor_kesiapan_adopsi',
])
->orderBy('created_at', 'desc');
if ($request->search) {
@@ -53,12 +60,12 @@ class PetaniController extends Controller
$summaryPetaniIds = (clone $query)->pluck('id');
$petani = $query->paginate($request->per_page ?? 10);
$komoditas = Komoditas::where('is_utama', true)->get();
$lahan = Lahan::whereIn('petani_id', $summaryPetaniIds)
->whereIn('komoditas_id', $komoditas->pluck('id'))
->get();
$tanaman = Tanaman::whereIn('lahan_id', $lahan->pluck('id'))
->get();
$komoditas = Komoditas::select('id', 'nama')->where('is_utama', true)->get();
$lahanQuery = Lahan::whereIn('petani_id', $summaryPetaniIds)
->whereIn('komoditas_id', $komoditas->pluck('id'));
$lahanIds = (clone $lahanQuery)->pluck('id');
$totalLuasLahan = (clone $lahanQuery)->sum('luas_lahan');
$totalTanaman = Tanaman::whereIn('lahan_id', $lahanIds)->count();
$case = "
CASE
@@ -74,7 +81,7 @@ class PetaniController extends Controller
->groupByRaw($case)
->get();
return view('produktivitas.petani.index', compact('petani', 'provinsi', 'lahan', 'komoditas', 'tanaman', 'skor'));
return view('produktivitas.petani.index', compact('petani', 'provinsi', 'komoditas', 'skor', 'totalLuasLahan', 'totalTanaman'));
}
public function create()
@@ -3,26 +3,43 @@
namespace App\Http\Controllers\Web\Produktivitas;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use App\Models\Pertanian\Petani;
use App\Models\Pertanian\SurveyProduktivitas;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
class SurveyProduktivitasController extends Controller
{
public function store($petaniId, Request $request)
{
$petani = Petani::findOrFail($petaniId);
$validated = $request->validate([
'produktivitas_komoditas' => ['required', 'array'],
'produktivitas_komoditas.*.komoditas_id' => ['nullable', 'exists:master_komoditas,id'],
'produktivitas_komoditas.*.hasil_panen_3_musim' => ['nullable', 'numeric'],
'produktivitas_komoditas.*.satuan' => ['nullable', 'string'],
$validator = Validator::make($request->all(), [
'produktivitas_komoditas' => ['required', 'array', 'min:1'],
'produktivitas_komoditas.*.komoditas_id' => ['required', 'exists:master_komoditas,id'],
'produktivitas_komoditas.*.hasil_panen_3_musim' => ['required', 'numeric', 'min:0'],
'produktivitas_komoditas.*.satuan' => ['required', 'in:ha_tahun,pohon_tahun'],
], [
'produktivitas_komoditas.required' => 'Minimal satu data produktivitas harus diisi.',
'produktivitas_komoditas.*.komoditas_id.required' => 'Komoditas wajib dipilih.',
'produktivitas_komoditas.*.komoditas_id.exists' => 'Komoditas yang dipilih tidak valid.',
'produktivitas_komoditas.*.hasil_panen_3_musim.required' => 'Hasil panen wajib diisi.',
'produktivitas_komoditas.*.hasil_panen_3_musim.numeric' => 'Hasil panen harus berupa angka.',
'produktivitas_komoditas.*.hasil_panen_3_musim.min' => 'Hasil panen tidak boleh kurang dari 0.',
'produktivitas_komoditas.*.satuan.required' => 'Satuan wajib dipilih.',
'produktivitas_komoditas.*.satuan.in' => 'Satuan yang dipilih tidak valid.',
]);
if ($validator->fails()) {
return $this->redirectBackToFragment($request)->withErrors($validator)->withInput();
}
$validated = $validator->validated();
foreach ($validated['produktivitas_komoditas'] as $row) {
SurveyProduktivitas::create([
'uid' => 'SPV-' . strtoupper(Str::random(10)),
'uid' => 'SPV-'.strtoupper(Str::random(10)),
'petani_id' => $petani->id,
'komoditas_id' => $row['komoditas_id'],
'kuantitas' => $row['hasil_panen_3_musim'],
@@ -51,10 +68,10 @@ class SurveyProduktivitasController extends Controller
{
$fragment = $request->input('redirect_fragment');
if (!is_string($fragment) || !preg_match('/^[A-Za-z0-9_-]+$/', $fragment)) {
if (! is_string($fragment) || ! preg_match('/^[A-Za-z0-9_-]+$/', $fragment)) {
return back();
}
return redirect()->to(Str::before(url()->previous(), '#') . '#' . $fragment);
return redirect()->to(Str::before(url()->previous(), '#').'#'.$fragment);
}
}
+108
View File
@@ -0,0 +1,108 @@
<?php
namespace App\Models\Bumdes;
use App\Enums\Bumdes\JabatanBumdes;
use App\Enums\Pendidikan;
use App\Models\User;
use App\Models\Wilayah\DesaKelurahan;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class PengurusBumdes extends Model
{
use SoftDeletes;
protected $table = 'bumdes_pengurus';
protected $fillable = [
'uid',
'nama',
'jenis_kelamin',
'tempat_lahir',
'tanggal_lahir',
'pendidikan_terakhir',
'alamat',
'desa_kelurahan_id',
'nomor_telepon',
'jabatan',
'jabatan_lainnya',
'lama_menjabat_tahun',
'tanggal_mulai_menjabat',
'created_by',
'updated_by',
'deleted_by',
];
protected $casts = [
'jenis_kelamin' => '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');
}
}
@@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('bumdes_pengurus', function (Blueprint $table) {
$table->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');
}
};
@@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('bumdes_pengurus', function (Blueprint $table) {
if (! Schema::hasColumn('bumdes_pengurus', 'pendidikan_terakhir')) {
$table->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');
}
});
}
};
@@ -0,0 +1,7 @@
@extends('layout.main')
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
@include('bumdes.profil.header', ['pengurus' => $pengurus])
</div>
@endsection
@@ -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
<h5 class="pb-4 border-bottom mb-4">Data Pribadi</h5>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-nama">Nama Pengurus BUMDes<span class="text-danger">*</span></label>
<input type="text" class="form-control @error('nama') is-invalid @enderror" id="{{ $prefix }}-nama" name="nama" placeholder="Contoh: John Doe" value="{{ old('nama', $pengurus?->nama) }}" />
@error('nama')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-jenis-kelamin">Jenis Kelamin<span class="text-danger">*</span></label>
<select class="form-control @error('jenis_kelamin') is-invalid @enderror" id="{{ $prefix }}-jenis-kelamin" name="jenis_kelamin">
<option value="">Pilih Jenis Kelamin</option>
<option value="1" {{ old('jenis_kelamin', $pengurus?->jenis_kelamin) == '1' ? 'selected' : '' }}>Laki-laki</option>
<option value="0" {{ old('jenis_kelamin', $pengurus?->jenis_kelamin) == '0' ? 'selected' : '' }}>Perempuan</option>
</select>
@error('jenis_kelamin')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-tempat-lahir">Tempat Lahir<span class="text-danger">*</span></label>
<input type="text" class="form-control @error('tempat_lahir') is-invalid @enderror" id="{{ $prefix }}-tempat-lahir" name="tempat_lahir" placeholder="Contoh: Ngada" value="{{ old('tempat_lahir', $pengurus?->tempat_lahir) }}" />
@error('tempat_lahir')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-tanggal-lahir">Tanggal Lahir<span class="text-danger">*</span></label>
<input type="text" class="form-control @error('tanggal_lahir') is-invalid @enderror" id="{{ $prefix }}-tanggal-lahir" name="tanggal_lahir" value="{{ old('tanggal_lahir', $pengurus?->tanggal_lahir?->format('d-m-Y')) }}" />
@error('tanggal_lahir')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-pendidikan-terakhir">Pendidikan Terakhir<span class="text-danger">*</span></label>
<select class="form-control @error('pendidikan_terakhir') is-invalid @enderror" id="{{ $prefix }}-pendidikan-terakhir" name="pendidikan_terakhir">
<option value="">Pilih Pendidikan Terakhir</option>
@foreach($pendidikan as $value)
<option value="{{ $value['value'] }}" {{ old('pendidikan_terakhir', $currentPendidikan) == $value['value'] ? 'selected' : '' }}>{{ $value['label'] }}</option>
@endforeach
</select>
@error('pendidikan_terakhir')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<h5 class="pb-4 border-bottom mb-4 mt-4">Peran Kepengurusan BUMDes</h5>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-jabatan">Jabatan/Peran<span class="text-danger">*</span></label>
<select class="form-control @error('jabatan') is-invalid @enderror" id="{{ $prefix }}-jabatan" name="jabatan">
<option value="">Pilih Jabatan/Peran</option>
@foreach($jabatan as $value)
<option value="{{ $value['value'] }}" {{ old('jabatan', $currentJabatan) == $value['value'] ? 'selected' : '' }}>{{ $value['label'] }}</option>
@endforeach
</select>
@error('jabatan')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation {{ old('jabatan', $currentJabatan) === \App\Enums\Bumdes\JabatanBumdes::LAINNYA->value ? '' : 'd-none' }}" id="{{ $prefix }}-jabatan-lainnya-wrapper">
<label class="form-label" for="{{ $prefix }}-jabatan-lainnya">Jabatan Lainnya<span class="text-danger">*</span></label>
<input type="text" class="form-control @error('jabatan_lainnya') is-invalid @enderror" id="{{ $prefix }}-jabatan-lainnya" name="jabatan_lainnya" placeholder="Contoh: Kepala Unit Usaha" value="{{ old('jabatan_lainnya', $pengurus?->jabatan_lainnya) }}" />
@error('jabatan_lainnya')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-lama-menjabat">Lama Menjabat (Tahun)<span class="text-danger">*</span></label>
<input type="number" min="0" max="80" class="form-control @error('lama_menjabat_tahun') is-invalid @enderror" id="{{ $prefix }}-lama-menjabat" name="lama_menjabat_tahun" placeholder="Contoh: 2" value="{{ old('lama_menjabat_tahun', $pengurus?->lama_menjabat_tahun) }}" />
@error('lama_menjabat_tahun')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<h5 class="pb-4 border-bottom mb-4 mt-4">Domisili dan Kontak</h5>
<div class="row">
<div class="col-md-12 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-alamat">Alamat<span class="text-danger">*</span></label>
<textarea class="form-control @error('alamat') is-invalid @enderror" id="{{ $prefix }}-alamat" name="alamat" rows="2" placeholder="Contoh: Jl. Nama Jalan, Nama Dusun">{{ old('alamat', $pengurus?->alamat) }}</textarea>
@error('alamat')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-provinsi">Provinsi<span class="text-danger">*</span></label>
<select class="form-control @error('provinsi_id') is-invalid @enderror" id="{{ $prefix }}-provinsi" name="provinsi_id">
<option value="">Pilih Provinsi</option>
@foreach($provinsi as $p)
<option value="{{ $p->id }}" {{ $currentProvinsiId == $p->id ? 'selected' : '' }}>{{ $p->nama }}</option>
@endforeach
</select>
@error('provinsi_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-kabupaten">Kabupaten/Kota<span class="text-danger">*</span></label>
<select class="form-control @error('kabupaten_id') is-invalid @enderror" id="{{ $prefix }}-kabupaten" name="kabupaten_id">
<option value="">Pilih Kabupaten/Kota</option>
@if($currentKabupaten)
<option value="{{ $currentKabupaten->id }}" selected>{{ $currentKabupaten->nama }}</option>
@endif
</select>
@error('kabupaten_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-kecamatan">Kecamatan<span class="text-danger">*</span></label>
<select class="form-control @error('kecamatan_id') is-invalid @enderror" id="{{ $prefix }}-kecamatan" name="kecamatan_id">
<option value="">Pilih Kecamatan</option>
@if($currentKecamatan)
<option value="{{ $currentKecamatan->id }}" selected>{{ $currentKecamatan->nama }}</option>
@endif
</select>
@error('kecamatan_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-desa">Desa/Kelurahan<span class="text-danger">*</span></label>
<select class="form-control @error('desa_kelurahan_id') is-invalid @enderror" id="{{ $prefix }}-desa" name="desa_kelurahan_id">
<option value="">Pilih Desa/Kelurahan</option>
@if($currentDesa)
<option value="{{ $currentDesa->id }}" selected>{{ $currentDesa->nama }}</option>
@endif
</select>
@error('desa_kelurahan_id')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
<div class="row">
<div class="col-md-3 mb-4 form-control-validation">
<label class="form-label" for="{{ $prefix }}-nomor-telepon">No HP</label>
<input type="text" class="form-control @error('nomor_telepon') is-invalid @enderror" id="{{ $prefix }}-nomor-telepon" name="nomor_telepon" placeholder="Contoh: 081234567890" value="{{ old('nomor_telepon', $pengurus?->nomor_telepon) }}" minlength="11" maxlength="13" />
@error('nomor_telepon')<div class="error invalid-feedback">{{ $message }}</div>@enderror
</div>
</div>
@push('scripts')
<script>
'use strict';
$(document).ready(function () {
const prefix = '#{{ $prefix }}';
const lainnyaValue = '{{ \App\Enums\Bumdes\JabatanBumdes::LAINNYA->value }}';
$(`${prefix}-jenis-kelamin, ${prefix}-pendidikan-terakhir, ${prefix}-jabatan`).select2();
$(`${prefix}-tanggal-lahir`).flatpickr({
dateFormat: 'd-m-Y'
});
function toggleJabatanLainnya() {
const isLainnya = $(`${prefix}-jabatan`).val() === lainnyaValue;
$(`${prefix}-jabatan-lainnya-wrapper`).toggleClass('d-none', !isLainnya);
if (!isLainnya) {
$(`${prefix}-jabatan-lainnya`).val('');
}
}
$(`${prefix}-jabatan`).on('change', toggleJabatanLainnya);
toggleJabatanLainnya();
$(`${prefix}-provinsi`).select2().change(function(e) {
e.preventDefault();
const provinsiId = $(this).val();
$(`${prefix}-kabupaten`).prop('disabled', !provinsiId).val('').trigger('change');
$(`${prefix}-kecamatan`).prop('disabled', true).val('').trigger('change');
$(`${prefix}-desa`).prop('disabled', true).val('').trigger('change');
if (provinsiId) {
$.ajax({
url: '{{ route("kabupatenkota.byprovinsi", ":id") }}'.replace(':id', provinsiId),
method: 'GET',
success: function(data) {
$(`${prefix}-kabupaten`).empty().append('<option value="">Pilih Kabupaten/Kota</option>');
data.forEach(function(kabupaten) {
$(`${prefix}-kabupaten`).append('<option value="' + kabupaten.id + '">' + kabupaten.nama + '</option>');
});
}
});
}
});
$(`${prefix}-kabupaten`).select2().change(function(e) {
e.preventDefault();
const kabupatenId = $(this).val();
$(`${prefix}-kecamatan`).prop('disabled', !kabupatenId).val('').trigger('change');
$(`${prefix}-desa`).prop('disabled', true).val('').trigger('change');
if (kabupatenId) {
$.ajax({
url: '{{ route("kecamatan.bykabupatenkota", ":id") }}'.replace(':id', kabupatenId),
method: 'GET',
success: function(data) {
$(`${prefix}-kecamatan`).empty().append('<option value="">Pilih Kecamatan</option>');
data.forEach(function(kecamatan) {
$(`${prefix}-kecamatan`).append('<option value="' + kecamatan.id + '">' + kecamatan.nama + '</option>');
});
}
});
}
});
$(`${prefix}-kecamatan`).select2().change(function(e) {
e.preventDefault();
const kecamatanId = $(this).val();
$(`${prefix}-desa`).prop('disabled', !kecamatanId).val('').trigger('change');
if (kecamatanId) {
$.ajax({
url: '{{ route("desakelurahan.bykecamatan", ":id") }}'.replace(':id', kecamatanId),
method: 'GET',
success: function(data) {
$(`${prefix}-desa`).empty().append('<option value="">Pilih Desa/Kelurahan</option>');
data.forEach(function(desa) {
$(`${prefix}-desa`).append('<option value="' + desa.id + '">' + desa.nama + '</option>');
});
}
});
}
});
$(`${prefix}-desa`).select2();
$('#{{ $mode }}BumdesForm').validate({
rules: {
nama: { required: true },
jenis_kelamin: { required: true },
tempat_lahir: { required: true },
tanggal_lahir: { required: true },
pendidikan_terakhir: { required: true },
jabatan: { required: true },
jabatan_lainnya: {
required: function() {
return $(`${prefix}-jabatan`).val() === lainnyaValue;
}
},
lama_menjabat_tahun: { required: true, digits: true, min: 0, max: 80 },
alamat: { required: true },
provinsi_id: { required: true },
kabupaten_id: { required: true },
kecamatan_id: { required: true },
desa_kelurahan_id: { required: true },
nomor_telepon: { required: false, digits: true, minlength: 11, maxlength: 13 }
},
messages: {
nama: { required: 'Nama pengurus BUMDes wajib diisi' },
jenis_kelamin: { required: 'Jenis kelamin wajib dipilih' },
tempat_lahir: { required: 'Tempat lahir wajib diisi' },
tanggal_lahir: { required: 'Tanggal lahir wajib diisi' },
pendidikan_terakhir: { required: 'Pendidikan terakhir wajib dipilih' },
jabatan: { required: 'Jabatan/peran wajib dipilih' },
jabatan_lainnya: { required: 'Jabatan lainnya wajib diisi' },
lama_menjabat_tahun: {
required: 'Lama menjabat wajib diisi',
digits: 'Lama menjabat harus berupa angka tahun',
min: 'Lama menjabat tidak boleh kurang dari 0 tahun',
max: 'Lama menjabat tidak boleh lebih dari 80 tahun'
},
alamat: { required: 'Alamat wajib diisi' },
provinsi_id: { required: 'Provinsi wajib dipilih' },
kabupaten_id: { required: 'Kabupaten/Kota wajib dipilih' },
kecamatan_id: { required: 'Kecamatan wajib dipilih' },
desa_kelurahan_id: { required: 'Desa/Kelurahan wajib dipilih' },
nomor_telepon: {
digits: 'Nomor telepon harus berupa angka',
minlength: 'Nomor telepon minimal 11 digit',
maxlength: 'Nomor telepon maksimal 13 digit'
}
},
errorElement: 'div',
errorPlacement: function (error, element) {
error.addClass('invalid-feedback');
element.closest('.form-control-validation').append(error);
},
highlight: function (element) {
$(element).addClass('is-invalid');
},
unhighlight: function (element) {
$(element).removeClass('is-invalid');
}
});
});
</script>
@endpush
@@ -0,0 +1,34 @@
@extends('layout.main')
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
@if ($errors->any())
<div class="alert alert-danger">
<ul class="mb-0">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
@include('bumdes.profil.header', ['pengurus' => null])
<div class="card mb-6">
<div class="card-header border-bottom">
<h5 class="card-title mb-0">Tambah Profil Pengurus BUMDes</h5>
</div>
<div class="card-body pt-6">
<form id="addBumdesForm" action="{{ route('bumdes.store') }}" method="POST">
@csrf
@include('bumdes.profil._form', ['pengurus' => null, 'mode' => 'add'])
<div class="mt-4 text-end">
<a href="{{ route('bumdes.index') }}" class="btn btn-secondary me-2 wave-effect wave-light">Kembali</a>
<button type="submit" class="btn btn-success data-submit wave-effect wave-light"><i class="ti tabler-device-floppy me-2"></i> Simpan Profil</button>
</div>
</form>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,39 @@
@extends('layout.main')
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
@if (session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
@if ($errors->any())
<div class="alert alert-danger">
<ul class="mb-0">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
@include('bumdes.profil.header', ['pengurus' => $pengurus])
<div class="card mb-6">
<div class="card-header border-bottom">
<h5 class="card-title mb-0">Edit Profil Pengurus BUMDes</h5>
</div>
<div class="card-body pt-6">
<form id="editBumdesForm" action="{{ route('bumdes.update', $pengurus->id) }}" method="POST">
@csrf
@method('PUT')
@include('bumdes.profil._form', ['pengurus' => $pengurus, 'mode' => 'edit'])
<div class="mt-4 text-end">
<a href="{{ route('bumdes.index') }}" class="btn btn-secondary me-2 wave-effect wave-light">Kembali</a>
<button type="submit" class="btn btn-success data-submit wave-effect wave-light"><i class="ti tabler-device-floppy me-2"></i> Simpan Profil</button>
</div>
</form>
</div>
</div>
</div>
@endsection
@@ -0,0 +1,162 @@
<style>
@media (min-width: 768px) {
.nav-pills-custom-spacing {
display: flex;
width: 100%;
gap: 0.5rem;
flex-wrap: nowrap !important;
overflow-x: auto;
}
.nav-pills-custom-spacing::-webkit-scrollbar {
display: none;
}
.nav-pills-custom-spacing .nav-item {
margin-right: 0 !important;
flex: 1;
}
.nav-pills-custom-spacing .nav-link {
display: flex;
justify-content: center;
align-items: center;
padding-left: 0.5rem !important;
padding-right: 0.5rem !important;
width: 100%;
white-space: nowrap;
font-size: 0.9375rem !important;
}
.nav-pills-custom-spacing .nav-link i {
margin-right: 0.4rem !important;
}
}
</style>
@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
<div class="row mb-4">
<div class="col-md-4 mb-2 mb-md-0">
<div class="card h-100">
<div class="card-body p-3">
<h6 class="card-title mb-2">Profil Pengurus BUMDes</h6>
<div class="d-flex justify-content-start align-items-center mb-3">
<div class="avatar me-2">
<span class="avatar-initial rounded bg-label-primary">
<i class="icon-base ti tabler-user-check icon-22px"></i>
</span>
</div>
<div class="d-flex flex-column">
<h6 class="mb-0" style="font-size: 0.9rem;">{{ isset($pengurus) ? $pengurus->nama : 'Tambah Pengurus BUMDes Baru' }}</h6>
<span class="text-muted" style="font-size: 0.75rem;">{{ $jenisKelamin }}</span>
<span class="text-muted" style="font-size: 0.75rem;">Jabatan: {{ $jabatanLabel }}</span>
</div>
</div>
<hr class="my-2">
<h6 class="mb-1" style="font-size: 0.85rem;">Domisili</h6>
<p class="mb-0 text-muted" style="font-size: 0.75rem;">Alamat: {{ isset($pengurus) ? $pengurus->alamat : 'Alamat' }}</p>
<p class="mb-0 text-muted" style="font-size: 0.75rem; line-height: 1.3;">{{ $domisili }}</p>
</div>
</div>
</div>
<div class="col-md-8 d-flex flex-column">
<div class="card mb-2 flex-grow-1">
<div class="card-widget-separator-wrapper h-100">
<div class="card-body card-widget-separator py-2 h-100 d-flex flex-column justify-content-center">
<div class="row gy-2">
<div class="col-sm-6 col-lg-4">
<div class="d-flex justify-content-between align-items-center card-widget-1 border-end h-100 pe-3">
<div>
<p class="mb-0 text-muted" style="font-size: 0.75rem;">Jenis Kelamin</p>
<h5 class="mb-0">{{ $jenisKelamin }}</h5>
<p class="mb-0" style="font-size: 0.75rem;">
<span class="me-1">{{ isset($pengurus) ? ($pengurus->usia . ' tahun') : 'Belum terisi' }}</span>
</p>
</div>
<span class="avatar">
<span class="avatar-initial rounded">
<i class="icon-base ti tabler-users icon-22px text-heading"></i>
</span>
</span>
</div>
</div>
<div class="col-sm-6 col-lg-4">
<div class="d-flex justify-content-between align-items-center card-widget-1 border-end h-100 px-3">
<div>
<p class="mb-0 text-muted" style="font-size: 0.75rem;">Jabatan</p>
<h5 class="mb-0">{{ $jabatanLabel }}</h5>
<p class="mb-0" style="font-size: 0.75rem;">
<span class="me-1">{{ isset($pengurus) ? $pengurus->lama_menjabat : 'Belum terisi' }}</span>
</p>
</div>
<span class="avatar">
<span class="avatar-initial rounded">
<i class="icon-base ti tabler-briefcase icon-22px text-heading"></i>
</span>
</span>
</div>
</div>
<div class="col-sm-6 col-lg-4">
<div class="d-flex justify-content-between align-items-center card-widget-1 h-100 ps-3">
<div>
<p class="mb-0 text-muted" style="font-size: 0.75rem;">Domisili</p>
<h5 class="mb-0">{{ isset($pengurus) ? ($pengurus->desaKelurahan?->nama ?? '-') : '-' }}</h5>
<p class="mb-0" style="font-size: 0.75rem;">
<span class="me-1">{{ isset($pengurus) ? ($pengurus->desaKelurahan?->kecamatan?->nama ?? '-') : 'Belum terisi' }}</span>
</p>
</div>
<span class="avatar">
<span class="avatar-initial rounded">
<i class="icon-base ti tabler-map-pin icon-22px text-heading"></i>
</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card flex-grow-1">
<div class="card-body py-3 d-flex align-items-center">
<div class="w-100">
<p class="mb-1 text-muted" style="font-size: 0.75rem;">Alamat Domisili</p>
<h6 class="mb-0">{{ isset($pengurus) ? ($pengurus->alamat ?: '-') : '-' }}</h6>
<p class="mb-0 text-muted" style="font-size: 0.75rem;">{{ $domisili }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="nav-align-top">
<ul class="nav nav-pills flex-column flex-md-row mb-6 row-gap-2 nav-pills-custom-spacing">
<li class="nav-item">
<a class="nav-link {{ request()->routeIs('bumdes.create') || request()->routeIs('bumdes.edit') ? 'active' : '' }}" href="{{ isset($pengurus) ? route('bumdes.edit', $pengurus->id) : route('bumdes.create') }}">
<i class="icon-base ti tabler-user-check icon-sm"></i>Profil
</a>
</li>
<li class="nav-item">
@if(isset($pengurus))
<a class="nav-link {{ request()->routeIs('bumdes.kelembagaan-aktor.*') ? 'active' : '' }}" href="{{ route('bumdes.kelembagaan-aktor.index', $pengurus->id) }}">
<i class="icon-base ti tabler-building-community icon-sm"></i>Kelembagaan dan Aktor
</a>
@else
<a class="nav-link" href="#" disabled data-bs-original-title="Kelembagaan dan Aktor, isi profil terlebih dahulu" data-bs-toggle="tooltip" data-bs-placement="top">
<i class="icon-base ti tabler-building-community icon-sm"></i>Kelembagaan dan Aktor
</a>
@endif
</li>
</ul>
</div>
@@ -0,0 +1,158 @@
@extends('layout.main')
@section('content')
<div class="container-xxl flex-grow-1 container-p-y">
<div class="d-flex flex-row gap-3 mb-4">
<div class="w-25">
<x-summary-card
title="Pengurus BUMDes"
count="{{ $totalPengurus }}"
subtitle="{{ $totalLakiLaki }} Laki-laki, {{ $totalPerempuan }} Perempuan"
icon="user-check"
color="primary"
/>
</div>
<div class="w-25">
<x-summary-card
title="Desa/Kelurahan"
count="{{ $totalDesaKelurahan }}"
subtitle="desa/kelurahan memiliki data pengurus"
icon="map-pin"
color="success"
/>
</div>
<div class="w-25">
<x-summary-card
title="Jabatan/Peran"
count="{{ $totalJabatan }}"
subtitle="jenis jabatan/peran terdata"
icon="briefcase"
color="info"
/>
</div>
</div>
<div class="card">
<div class="card-header border-bottom">
<h5 class="card-title mb-0">Data Pengurus BUMDes</h5>
</div>
<div class="card-body border-bottom pt-4">
<form method="GET" action="{{ route('bumdes.index') }}" class="d-flex justify-content-between align-items-center row gap-3 gap-md-0">
<div class="col-md-auto">
<div class="d-flex align-items-center">
<label class="me-2 text-nowrap">Show</label>
<select name="per_page" class="form-select form-select-sm w-auto" onchange="this.form.submit()">
<option value="10" {{ request('per_page') == 10 ? 'selected' : '' }}>10</option>
<option value="25" {{ request('per_page') == 25 ? 'selected' : '' }}>25</option>
</select>
<label class="ms-2 text-nowrap">entries</label>
</div>
</div>
<div class="col-md-auto d-flex gap-2">
<div class="input-group input-group-sm w-auto">
<input type="text" name="search" class="form-control" placeholder="Cari Nama..." value="{{ request('search') }}">
<button type="submit" class="btn btn-outline-primary"><i class="ti tabler-search"></i></button>
</div>
<a href="{{ route('bumdes.create') }}" class="btn btn-sm btn-primary">
<i class="ti tabler-plus me-1"></i> Tambah
</a>
</div>
</form>
</div>
<div class="table-responsive text-nowrap">
<table class="table table-hover">
<thead class="border-top">
<tr>
<th>No</th>
<th>Nama</th>
<th>Jenis Kelamin</th>
<th>Usia</th>
<th>Desa/Kelurahan</th>
<th>Jabatan/Peran</th>
<th>Lama Menjabat</th>
@if($showEnumerator)
<th>Nama Enumerator</th>
@endif
<th>Aksi</th>
</tr>
</thead>
<tbody>
@forelse($pengurus as $item)
<tr>
<td>{{ ($pengurus->firstItem() ?? 0) + $loop->index }}</td>
<td><span class="text-heading">{{ $item->nama }}</span></td>
<td><span class="text-muted">{{ $item->jenis_kelamin ? 'Laki-laki' : 'Perempuan' }}</span></td>
<td><span class="text-muted">{{ $item->usia }} tahun</span></td>
<td>
<span class="text-muted">
{{ $item->desaKelurahan?->nama }},
{{ $item->desaKelurahan?->kecamatan?->nama }},
{{ $item->desaKelurahan?->kecamatan?->kabupatenKota?->nama }},
{{ $item->desaKelurahan?->kecamatan?->kabupatenKota?->provinsi?->nama }}
</span>
</td>
<td>{{ $item->nama_jabatan }}</td>
<td><span class="text-muted">{{ $item->lama_menjabat }}</span></td>
@if($showEnumerator)
<td><span class="text-muted">{{ $item->creator?->name ?? '-' }}</span></td>
@endif
<td>
<div class="d-flex align-items-center">
<a href="{{ route('bumdes.edit', $item->id) }}" class="btn btn-icon btn-text-secondary rounded-pill edit-record"><i class="ti tabler-edit ti-md"></i></a>
<a href="javascript:;" class="btn btn-icon btn-text-secondary rounded-pill delete-record" data-id="{{ $item->id }}" data-nama="{{ $item->nama }}"><i class="ti tabler-trash ti-md"></i></a>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="{{ $showEnumerator ? 9 : 8 }}" class="text-center py-4">Tidak ada data ditemukan.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<div class="card-footer d-flex justify-content-center justify-content-md-end border-top">
{{ $pengurus->appends(request()->query())->links('pagination::bootstrap-5') }}
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
'use strict';
const csrfToken = "{{ csrf_token() }}";
$(document).ready(function () {
$(document).on('click', '.delete-record', function () {
const id = $(this).data('id');
const name = $(this).data('nama');
Swal.fire({
title: 'Apakah Anda yakin?',
text: `Profile "${name}" akan dihapus secara permanen!`,
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Ya, Hapus!',
customClass: { confirmButton: 'btn btn-primary me-3', cancelButton: 'btn btn-label-secondary' },
buttonsStyling: false
}).then(function (result) {
if (result.value) {
$.ajax({
url: '{{ route('bumdes.destroy', ':id') }}'.replace(':id', id),
type: 'DELETE',
headers: { 'X-CSRF-TOKEN': csrfToken },
success: function (res) {
Swal.fire({ icon: 'success', title: 'Terhapus!', text: res.message, showConfirmButton: false, timer: 1500 })
.then(() => window.location.reload());
},
error: () => Swal.fire({ icon: 'error', title: 'Gagal!', text: 'Terjadi kesalahan sistem.' })
});
}
});
});
});
</script>
@endpush
+35
View File
@@ -3,6 +3,7 @@
<a href="{{ route('home') }}" class="app-brand-link">
<span class="app-brand-logo demo">
<span>
<!-- AgroMonev -->
<svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.3" d="M16 2.5C16 2.5 5 6.5 5 15.5C5 20.5 11 23.5 16 23.5V2.5Z" fill="#28a745" />
<path opacity="0.6" d="M16 2.5C16 2.5 27 6.5 27 15.5C27 20.5 21 23.5 16 23.5V2.5Z" fill="#28a745" />
@@ -10,6 +11,24 @@
<path d="M15 15L27 4" stroke="#ED1C24" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
<circle cx="27" cy="4" r="2.5" fill="#ED1C24" />
</svg>
<!-- AgroPro -->
<!-- <svg width="32" height="24" viewBox="0 0 32 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.25" d="M16 2.5C16 2.5 5 6.5 5 15.5C5 20.5 11 23.5 16 23.5V2.5Z" fill="#28A745"/>
<path opacity="0.5" d="M16 2.5C16 2.5 27 6.5 27 15.5C27 20.5 21 23.5 16 23.5V2.5Z" fill="#28A745"/>
<rect x="5.5" y="5.5" width="21" height="15" rx="2.5" fill="white" stroke="#0054A6" stroke-width="1.5"/>
<rect x="11" y="3.5" width="10" height="4" rx="2" fill="#0054A6"/>
<circle cx="9.5" cy="10" r="1.7" fill="#28A745"/>
<path d="M8.7 10L9.3 10.6L10.4 9.3" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 10H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 10H22" stroke="#0054A6" stroke-width="2" stroke-linecap="round"/>
<circle cx="9.5" cy="14" r="1.7" fill="#28A745"/>
<path d="M8.7 14L9.3 14.6L10.4 13.3" stroke="white" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13 14H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 14H19.5" stroke="#F4B400" stroke-width="2" stroke-linecap="round"/>
<circle cx="9.5" cy="18" r="1.7" fill="white" stroke="#ED1C24" stroke-width="1.3"/>
<path d="M13 18H23" stroke="#D9E2EC" stroke-width="2" stroke-linecap="round"/>
<path d="M13 18H17" stroke="#ED1C24" stroke-width="2" stroke-linecap="round"/>
</svg> -->
</span>
</span>
@@ -64,6 +83,13 @@
</a>
</li>
</ul>
<ul class="menu-sub">
<li class="menu-item {{ request()->routeIs('dashboard.bumdes') ? 'active' : '' }}">
<a href="{{ route('dashboard.bumdes') }}" class="menu-link">
<div data-i18n="Profil Pengurus BUMDes">Profil Pengurus BUMDes</div>
</a>
</li>
</ul>
@endif
</li>
@endif
@@ -78,6 +104,15 @@
<div data-i18n="Profil Petani">Profil Petani</div>
</a>
</li>
<li class="menu-header small">
<span class="menu-header-text" data-i18n="Data BUMDes">Data BUMDes</span>
</li>
<li class="menu-item {{ request()->routeIs('bumdes.*') ? 'active' : '' }}">
<a href="{{ route('bumdes.index') }}" class="menu-link">
<i class="menu-icon icon-base ti tabler-file-description"></i>
<div data-i18n="Profil Pengurus BUMDes">Profil Pengurus BUMDes</div>
</a>
</li>
@endif
@if(in_array($userRole, ['super_admin', 'admin']) && env('APP_NAME') == 'AgroPro')
@@ -15,8 +15,8 @@
<div class="w-25">
<x-summary-card
title="Lahan & Tanaman"
count="{{ number_format(($lahan?->sum('luas_lahan') ?? 0) / 10000, 2, ',', '.') }} ha"
subtitle="{{ $tanaman?->count() }} tanaman dari {{ $komoditas?->count() }} komoditas utama"
count="{{ number_format(($totalLuasLahan ?? 0) / 10000, 2, ',', '.') }} ha"
subtitle="{{ $totalTanaman ?? 0 }} tanaman dari {{ $komoditas?->count() }} komoditas utama"
icon="trees"
color="success"
/>
@@ -1598,42 +1598,66 @@
action="{{ route('petani.survey-produktivitas.store', $petani->id) }}"
class="form-repeater">
@csrf
<input type="hidden" name="redirect_fragment" value="section-kehilangan-hasil">
<input type="hidden" name="redirect_fragment" value="section-produktivitas">
@php
$produktivitasRows = old('produktivitas_komoditas');
if (!is_array($produktivitasRows) || count($produktivitasRows) === 0) {
$produktivitasRows = [
[
'komoditas_id' => null,
'hasil_panen_3_musim' => null,
'satuan' => null,
],
];
}
@endphp
<div data-repeater-list="produktivitas_komoditas">
@foreach ($produktivitasRows as $index => $produktivitasRow)
<div data-repeater-item>
<div class="row align-items-end">
<div class="col-md-4 mb-3">
<label class="form-label">Komoditas</label>
<select name="komoditas_id" class="form-select">
<select name="komoditas_id" class="form-select @error('produktivitas_komoditas.' . $index . '.komoditas_id') is-invalid @enderror">
<option value="">Pilih Komoditas</option>
@foreach ($komoditas as $item)
<option value="{{ $item->id }}">{{ $item->nama }}</option>
<option value="{{ $item->id }}" @selected((string) data_get($produktivitasRow, 'komoditas_id') === (string) $item->id)>{{ $item->nama }}</option>
@endforeach
</select>
@error('produktivitas_komoditas.' . $index . '.komoditas_id')
<div class="invalid-feedback d-block">{{ $message }}</div>
@enderror
</div>
<div class="col-md-3 mb-3">
<label class="form-label">Hasil</label>
<div class="input-group">
<input type="number" name="hasil_panen_3_musim" class="form-control" step="0.01" min="0">
<input type="number" name="hasil_panen_3_musim" class="form-control @error('produktivitas_komoditas.' . $index . '.hasil_panen_3_musim') is-invalid @enderror" step="0.01" min="0" value="{{ data_get($produktivitasRow, 'hasil_panen_3_musim') }}">
<span class="input-group-text">Kg</span>
</div>
@error('produktivitas_komoditas.' . $index . '.hasil_panen_3_musim')
<div class="invalid-feedback d-block">{{ $message }}</div>
@enderror
</div>
<div class="col-md-3 mb-3">
<label class="form-label d-block">Satuan</label>
<label class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="satuan" value="ha_tahun">
<input class="form-check-input @error('produktivitas_komoditas.' . $index . '.satuan') is-invalid @enderror" type="radio" name="satuan" value="ha_tahun" @checked(data_get($produktivitasRow, 'satuan') === 'ha_tahun')>
<span class="form-check-label">Ha/Tahun</span>
</label>
<label class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="satuan" value="pohon_tahun">
<input class="form-check-input @error('produktivitas_komoditas.' . $index . '.satuan') is-invalid @enderror" type="radio" name="satuan" value="pohon_tahun" @checked(data_get($produktivitasRow, 'satuan') === 'pohon_tahun')>
<span class="form-check-label">Pohon/Tahun</span>
</label>
@error('produktivitas_komoditas.' . $index . '.satuan')
<div class="invalid-feedback d-block">{{ $message }}</div>
@enderror
</div>
<div class="col-md-2 mb-3">
@@ -1645,6 +1669,7 @@
</div>
<hr>
</div>
@endforeach
</div>
<div class="mt-4 d-flex justify-content-between">
+5
View File
@@ -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);
});