Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/Console/Commands/updateAdminMenu.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public function handle()
setPermissionsTeamId($team->id);
if ($team) {
$team->menu = Modul::Menu;
$team->menu_order = null;
$team->save();

$role = Role::firstOrCreate(
Expand Down
6 changes: 6 additions & 0 deletions app/Enums/Modul.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ final class Modul extends Enum
'url' => 'bantuan',
'permission' => 'bantuan',
],
[
'text' => 'Kelembagaan',
'icon' => 'far fa-fw fa-circle',
'url' => 'lembaga',
'permission' => 'lembaga',
],
],
],
[
Expand Down
20 changes: 20 additions & 0 deletions app/Http/Controllers/LembagaController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class LembagaController extends Controller
{
public function index()
{
$title = 'Data Kelembagaan';

return view('lembaga.index', compact('title'));
}

public function cetak(Request $request)
{
return view('lembaga.cetak', ['filter' => $request->getQueryString()]);
}
}
1 change: 1 addition & 0 deletions catatan_rilis.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Di rilis ini, versi 2508.0.0 berisi penambahan dan perbaikan yang diminta penggu
7. [#797](https://github.com/OpenSID/OpenKab/issues/797) Penambahan kolom nama desa pada halaman ketenagakerjaan di OpenKab.
8. [#798](https://github.com/OpenSID/OpenKab/issues/798) Penambahan kolom nama desa pada beberapa halaman pendidikan di OpenKab.
9. [#798](https://github.com/OpenSID/OpenKab/issues/798) Penambahan kolom nama desa pada beberapa halaman pendidikan di OpenKab.
10. [#794](https://github.com/OpenSID/OpenKab/issues/794) Penambahan menu kelembagaan yang di ambil dari OpenSID.


#### Perbaikan BUG
Expand Down
26 changes: 26 additions & 0 deletions database/migrations/2025_08_20_091023_update_menu_admin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Artisan;

return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Artisan::call('admin:menu-update');
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
};
223 changes: 223 additions & 0 deletions resources/views/components/wilayah-filter-js.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
@props([
'kabupatenId' => 'filter_kabupaten',
'kecamatanId' => 'filter_kecamatan',
'desaId' => 'filter_desa',
'filterButtonId' => 'bt_filter',
'clearButtonId' => 'bt_clear_filter',
'onFilterChange' => null,
'apiUrl' => '',
'apiHeaders' => '{}',
'loadOnInit' => true,
])

@once
@push('js')
<script nonce="{{ csp_nonce() }}">
document.addEventListener("DOMContentLoaded", function() {
const wilayahFilter = {
kabupatenSelect: document.getElementById('{{ $kabupatenId }}'),
kecamatanSelect: document.getElementById('{{ $kecamatanId }}'),
desaSelect: document.getElementById('{{ $desaId }}'),
filterButton: document.getElementById('{{ $filterButtonId }}'),
clearButton: document.getElementById('{{ $clearButtonId }}'),
apiHeaders: {!! json_encode($apiHeaders) !!},

init() {
this.bindEvents();
@if ($loadOnInit)
this.loadKabupaten();
@endif
},

bindEvents() {
if (this.kabupatenSelect) {
this.kabupatenSelect.addEventListener('change', () => {
this.loadKecamatan();
this.clearDesa();
});
}

if (this.kecamatanSelect) {
this.kecamatanSelect.addEventListener('change', () => {
this.loadDesa();
});
}

if (this.filterButton) {
this.filterButton.addEventListener('click', () => {
this.applyFilter();
});
}

if (this.clearButton) {
this.clearButton.addEventListener('click', () => {
this.clearFilter();
});
}
},

async loadKabupaten() {
if (!this.kabupatenSelect) return;

try {
const apiUrl =
'{{ $apiUrl ?: config('app.databaseGabunganUrl') . '/api/v1/wilayah/kabupaten' }}';
const response = await fetch(apiUrl, {
headers: this.apiHeaders
});

if (!response.ok) throw new Error('Failed to load kabupaten');

const data = await response.json();
this.populateSelect(this.kabupatenSelect, data.data, 'kode_kabupaten',
'nama_kabupaten');
} catch (error) {
console.error('Error loading kabupaten:', error);
}
},

async loadKecamatan() {
if (!this.kecamatanSelect || !this.kabupatenSelect) return;

const kabupatenCode = this.kabupatenSelect.value;
if (!kabupatenCode) {
this.clearSelect(this.kecamatanSelect);
this.clearDesa();
return;
}

try {
const apiUrl =
'{{ $apiUrl ?: config('app.databaseGabunganUrl') . '/api/v1/wilayah/kecamatan' }}';
const url = new URL(apiUrl);
url.searchParams.set('kode_kabupaten', kabupatenCode);

const response = await fetch(url.href, {
headers: this.apiHeaders
});

if (!response.ok) throw new Error('Failed to load kecamatan');

const data = await response.json();
this.populateSelect(this.kecamatanSelect, data.data, 'kode_kecamatan',
'nama_kecamatan');
} catch (error) {
console.error('Error loading kecamatan:', error);
}
},

async loadDesa() {
if (!this.desaSelect || !this.kecamatanSelect) return;

const kecamatanCode = this.kecamatanSelect.value;
if (!kecamatanCode) {
this.clearSelect(this.desaSelect);
return;
}

try {
const apiUrl =
'{{ $apiUrl ?: config('app.databaseGabunganUrl') . '/api/v1/wilayah/desa' }}';
const url = new URL(apiUrl);
url.searchParams.set('kode_kecamatan', kecamatanCode);

const response = await fetch(url.href, {
headers: this.apiHeaders
});

if (!response.ok) throw new Error('Failed to load desa');

const data = await response.json();
this.populateSelect(this.desaSelect, data.data, 'kode_desa', 'nama_desa');
} catch (error) {
console.error('Error loading desa:', error);
}
},

populateSelect(selectElement, data, valueField, textField) {
// Clear existing options except the first one
const firstOption = selectElement.options[0];
selectElement.innerHTML = '';
selectElement.appendChild(firstOption);

// Add new options
data.forEach(item => {
const option = document.createElement('option');
option.value = item[valueField] || item.attributes[valueField];
option.textContent = item[textField] || item.attributes[textField];
selectElement.appendChild(option);
});
},

clearSelect(selectElement) {
if (!selectElement) return;

const firstOption = selectElement.options[0];
selectElement.innerHTML = '';
selectElement.appendChild(firstOption);
},

clearDesa() {
this.clearSelect(this.desaSelect);
},

applyFilter() {
const filterData = {
kabupaten: this.kabupatenSelect?.value || '',
kecamatan: this.kecamatanSelect?.value || '',
desa: this.desaSelect?.value || ''
};

@if ($onFilterChange)
{{ $onFilterChange }}(filterData);
@else
// Default behavior - trigger custom event
document.dispatchEvent(new CustomEvent('wilayahFilterChange', {
detail: filterData
}));
@endif
},

clearFilter() {
if (this.kabupatenSelect) this.kabupatenSelect.value = '';
if (this.kecamatanSelect) this.clearSelect(this.kecamatanSelect);
if (this.desaSelect) this.clearSelect(this.desaSelect);

// Trigger filter change with empty values
this.applyFilter();
},

getFilterValues() {
return {
kabupaten: this.kabupatenSelect?.value || '',
kecamatan: this.kecamatanSelect?.value || '',
desa: this.desaSelect?.value || ''
};
},

setFilterValues(values) {
if (values.kabupaten && this.kabupatenSelect) {
this.kabupatenSelect.value = values.kabupaten;
this.loadKecamatan().then(() => {
if (values.kecamatan && this.kecamatanSelect) {
this.kecamatanSelect.value = values.kecamatan;
this.loadDesa().then(() => {
if (values.desa && this.desaSelect) {
this.desaSelect.value = values.desa;
}
});
}
});
}
}
};

// Initialize the filter
wilayahFilter.init();

// Make it globally accessible
window.wilayahFilter = wilayahFilter;
});
</script>
@endpush
@endonce
84 changes: 84 additions & 0 deletions resources/views/components/wilayah-filter.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
@props([
'showKabupaten' => true,
'showKecamatan' => true,
'showDesa' => true,
'showButtons' => true,
'kabupatenLabel' => '',
'kecamatanLabel' => 'Kecamatan',
'desaLabel' => '',
'filterButtonText' => 'TAMPILKAN',
'clearButtonText' => 'HAPUS FILTER',
'containerClass' => 'row',
'columnClass' => 'col-md-3',
'buttonColumnClass' => 'col-md-3',
'kabupatenId' => 'filter_kabupaten',
'kecamatanId' => 'filter_kecamatan',
'desaId' => 'filter_desa',
'filterButtonId' => 'bt_filter',
'clearButtonId' => 'bt_clear_filter',
'includeJs' => true,
])

@php
$kabupatenLabelFinal = $kabupatenLabel ?: config('app.sebutanKab');
$desaLabelFinal = $desaLabel ?: config('app.sebutanDesa');
@endphp

<div class="{{ $containerClass }}">
@if ($showKabupaten)
<div class="{{ $columnClass }}">
<div class="form-group">
<label>{{ $kabupatenLabelFinal }}</label>
<select name="Filter {{ $kabupatenLabelFinal }}" id="{{ $kabupatenId }}" class="form-control"
title="Pilih {{ $kabupatenLabelFinal }}">
<option value="">Semua {{ $kabupatenLabelFinal }}</option>
</select>
</div>
</div>
@endif

@if ($showKecamatan)
<div class="{{ $columnClass }}">
<div class="form-group">
<label>{{ $kecamatanLabel }}</label>
<select name="Filter {{ $kecamatanLabel }}" id="{{ $kecamatanId }}" class="form-control"
title="Pilih {{ $kecamatanLabel }}">
<option value="">Semua {{ $kecamatanLabel }}</option>
</select>
</div>
</div>
@endif

@if ($showDesa)
<div class="{{ $columnClass }}">
<div class="form-group">
<label>{{ $desaLabelFinal }}</label>
<select name="Filter {{ $desaLabelFinal }}" id="{{ $desaId }}" class="form-control"
title="Pilih {{ $desaLabelFinal }}">
<option value="">Semua {{ $desaLabelFinal }}</option>
</select>
</div>
</div>
@endif

@if ($showButtons)
<div class="{{ $buttonColumnClass }}">
<div class="row">
<div class="col-6">
<button id="{{ $clearButtonId }}" class="btn btn-sm btn-danger btn-block">
{{ $clearButtonText }}
</button>
</div>
<div class="col-6">
<button id="{{ $filterButtonId }}" class="btn btn-sm btn-primary btn-block">
{{ $filterButtonText }}
</button>
</div>
</div>
</div>
@endif
</div>

@if ($includeJs)
@include('components.wilayah_filter_js')
@endif
Loading