Spaces:
Sleeping
Sleeping
| <html lang="id"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Alat Bantu Pencarian Data Bantuan Sosial</title> | |
| <style> | |
| /* --- Gaya Dasar & Tata Letak --- */ | |
| * { | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; | |
| color: #172b4d; | |
| margin: 1em; | |
| line-height: 1.5; | |
| } | |
| .cb-container { | |
| max-width: 900px; | |
| margin: auto; | |
| background: #ffffff; | |
| padding: 1.5em; | |
| border-radius: 8px; | |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); | |
| } | |
| .cb-grid { | |
| display: grid; | |
| grid-template-columns: 1fr; | |
| gap: 2.5em; | |
| } | |
| .cb-col h2, | |
| .cb-col h3 { | |
| border-bottom: 2px solid #dfe1e6; | |
| padding-bottom: 0.5em; | |
| margin-top: 0; | |
| margin-bottom: 1.2em; | |
| color: #091e42; | |
| } | |
| /* --- Formulir --- */ | |
| .cb-label { | |
| display: block; | |
| margin-bottom: 0.5em; | |
| font-weight: bold; | |
| font-size: 0.95em; | |
| color: #42526e; | |
| } | |
| .cb-select, | |
| .cb-input { | |
| width: 100%; | |
| padding: 0.85em; | |
| margin-bottom: 1.2em; | |
| border: 2px solid #dfe1e6; | |
| border-radius: 6px; | |
| background-color: #fafbfc; | |
| font-size: 1em; | |
| color: #172b4d; | |
| text-transform: uppercase; | |
| transition: border-color 0.2s; | |
| } | |
| .cb-select:focus, | |
| .cb-input:focus { | |
| border-color: #0052cc; | |
| outline: none; | |
| } | |
| .cb-select:disabled { | |
| background-color: #f4f5f7; | |
| cursor: not-allowed; | |
| } | |
| /* --- Tombol --- */ | |
| .cb-actions { | |
| display: flex; | |
| gap: 1em; | |
| margin-top: 1.5em; | |
| flex-direction: column; | |
| } | |
| .cb-btn { | |
| border: none; | |
| padding: 0.85em 1.5em; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| text-decoration: none; | |
| text-align: center; | |
| font-size: 1em; | |
| width: 100%; | |
| transition: background-color 0.2s; | |
| } | |
| .cb-btn-primary { | |
| background-color: #0052cc; | |
| color: white; | |
| } | |
| .cb-btn-primary:hover { | |
| background-color: #0747a6; | |
| } | |
| .cb-btn-gray { | |
| background-color: #ebecf0; | |
| color: #42526e; | |
| } | |
| .cb-btn-gray:hover { | |
| background-color: #dfe1e6; | |
| } | |
| /* --- Info & Disclaimer --- */ | |
| .cb-note, | |
| .cb-disclaimer { | |
| margin-top: 1.5em; | |
| padding: 1em; | |
| border-radius: 6px; | |
| font-size: 0.9em; | |
| } | |
| .cb-note { | |
| background-color: #e6fcff; | |
| border-left: 4px solid #00c7e6; | |
| } | |
| .cb-disclaimer { | |
| background-color: #fffae6; | |
| border-left: 4px solid #ffab00; | |
| } | |
| /* --- Kotak Hasil --- */ | |
| .cb-result { | |
| display: none; | |
| margin-top: 2.5em; | |
| padding: 1.5em; | |
| border-radius: 8px; | |
| background-color: #fafbfc; | |
| } | |
| .cb-kv { | |
| display: grid; | |
| grid-template-columns: 1fr; | |
| gap: 0.5em 1em; | |
| } | |
| .cb-kv div:nth-child(odd) { | |
| font-weight: bold; | |
| color: #6b778c; | |
| } | |
| /* Styling untuk nama kini sama dengan value lainnya */ | |
| .cb-kv div:nth-child(even) { | |
| font-weight: 600; | |
| } | |
| /* --- Desain Responsif --- */ | |
| @media (min-width: 600px) { | |
| .cb-actions { | |
| flex-direction: row; | |
| } | |
| .cb-btn { | |
| width: auto; | |
| } | |
| .cb-kv { | |
| grid-template-columns: 140px 1fr; | |
| } | |
| } | |
| @media (min-width: 900px) { | |
| .cb-container { | |
| padding: 2em; | |
| } | |
| .cb-grid { | |
| grid-template-columns: 2fr 1fr; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="cb-container" id="cek-bansos-tool"> | |
| <div class="cb-grid"> | |
| <div class="cb-col"> | |
| <h2>Pencarian Data Penerima Manfaat</h2> | |
| <label class="cb-label" for="provinsi">Provinsi</label> | |
| <select id="provinsi" class="cb-select"> | |
| <option value="">=== PILIH PROVINSI ===</option> | |
| </select> | |
| <label class="cb-label" for="kabupaten">Kabupaten/Kota</label> | |
| <select id="kabupaten" class="cb-select" disabled> | |
| <option value="">=== PILIH KABUPATEN/KOTA ===</option> | |
| </select> | |
| <label class="cb-label" for="kecamatan">Kecamatan</label> | |
| <select id="kecamatan" class="cb-select" disabled> | |
| <option value="">=== PILIH KECAMATAN ===</option> | |
| </select> | |
| <label class="cb-label" for="desa">Desa/Kelurahan</label> | |
| <select id="desa" class="cb-select" disabled> | |
| <option value="">=== PILIH DESA/KELURAHAN ===</option> | |
| </select> | |
| <label class="cb-label" for="nama">Nama Penerima (sesuai KTP)</label> | |
| <input id="nama" class="cb-input" type="text" placeholder="CONTOH: BUDI SANTOSO" /> | |
| <div class="cb-actions"> | |
| <button type="button" id="resetButton" class="cb-btn cb-btn-gray">Atur Ulang</button> | |
| <button type="button" id="searchButton" class="cb-btn cb-btn-primary">Cari Data</button> | |
| </div> | |
| <div class="cb-note"> | |
| <strong>Catatan:</strong> Ini adalah <em>alat bantu</em> untuk menyiapkan data Anda. Hasil resmi | |
| hanya tersedia di situs Kemensos. | |
| </div> | |
| </div> | |
| <div class="cb-col"> | |
| <h3>Cara Pakai (Singkat)</h3> | |
| <ol style="padding-left: 1.5em;"> | |
| <li>Pilih wilayah domisili lengkap secara berurutan.</li> | |
| <li>Ketik nama lengkap sesuai KTP.</li> | |
| <li>Klik <strong>Cari Data</strong> untuk melihat ringkasan & tombol menuju situs resmi.</li> | |
| </ol> | |
| <div class="cb-disclaimer"> | |
| <em>Sanggahan:</em> Website ini <strong>bukan</strong> situs resmi Kemensos. Kami hanya menyediakan | |
| panduan & tombol akses cepat ke layanan resmi. | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Result box --> | |
| <div id="resultBox" class="cb-result"> | |
| <h3>Ringkasan Data Anda</h3> | |
| <div class="cb-kv"> | |
| <div>Nama</div> | |
| <div id="r-nama">–</div> | |
| <div>Provinsi</div> | |
| <div id="r-prov">–</div> | |
| <div>Kab/Kota</div> | |
| <div id="r-kab">–</div> | |
| <div>Kecamatan</div> | |
| <div id="r-kec">–</div> | |
| <div>Desa/Kel</div> | |
| <div id="r-desa">–</div> | |
| </div> | |
| <p style="margin-top:1.5em; font-size: 0.95em;"> | |
| Untuk <strong>hasil resmi</strong>, lanjut ke layanan Kemensos di tab baru. Siapkan data yang sama saat | |
| mengisi. | |
| </p> | |
| <div class="cb-actions"> | |
| <a id="btn-resmi" class="cb-btn cb-btn-primary" href="https://cekbansos.kemensos.go.id" target="_blank" | |
| rel="nofollow noopener">Buka Situs Resmi Kemensos →</a> | |
| <button type="button" id="btn-copy" class="cb-btn cb-btn-gray" aria-label="Salin ringkasan"> | |
| <span id="copy-text">Salin Ringkasan</span> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', () => { | |
| const provinceSelect = document.getElementById('provinsi'); | |
| const regencySelect = document.getElementById('kabupaten'); | |
| const districtSelect = document.getElementById('kecamatan'); | |
| const villageSelect = document.getElementById('desa'); | |
| const nameInput = document.getElementById('nama'); | |
| const searchButton = document.getElementById('searchButton'); | |
| const resetButton = document.getElementById('resetButton'); | |
| const resultBox = document.getElementById('resultBox'); | |
| const copyButton = document.getElementById('btn-copy'); | |
| function populateSelect(selectElement, data, defaultOptionText) { | |
| selectElement.innerHTML = `<option value="">=== ${defaultOptionText.toUpperCase()} ===</option>`; | |
| data.forEach(item => { | |
| const option = document.createElement('option'); | |
| option.value = item.id; | |
| option.textContent = item.value; | |
| selectElement.appendChild(option); | |
| }); | |
| } | |
| function resetSelects(...selects) { | |
| selects.forEach(select => { | |
| const placeholder = select.options[0].text; | |
| select.innerHTML = `<option value="">${placeholder}</option>`; | |
| select.disabled = true; | |
| }); | |
| } | |
| async function fetchData(url) { | |
| try { | |
| const response = await fetch(url); | |
| if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); | |
| return await response.json(); | |
| } catch (error) { | |
| console.error("Gagal mengambil data:", error); | |
| alert("Gagal memuat data wilayah. Pastikan koneksi internet Anda stabil dan coba lagi."); | |
| return []; | |
| } | |
| } | |
| (async () => { | |
| const provinces = await fetchData('/api/provinces'); | |
| populateSelect(provinceSelect, provinces, 'Pilih Provinsi'); | |
| })(); | |
| provinceSelect.addEventListener('change', async () => { | |
| const provinceId = provinceSelect.value; | |
| resetSelects(regencySelect, districtSelect, villageSelect); | |
| resultBox.style.display = 'none'; | |
| if (provinceId) { | |
| let regencies = await fetchData(`/api/provinces/${provinceId}/regencies`); | |
| const formattedRegencies = regencies.map(reg => { | |
| const isCity = reg.value.toUpperCase().startsWith('KOTA'); | |
| return { id: reg.id, value: isCity ? reg.value : `KABUPATEN ${reg.value}` }; | |
| }); | |
| populateSelect(regencySelect, formattedRegencies, 'Pilih Kabupaten/Kota'); | |
| regencySelect.disabled = false; | |
| } | |
| }); | |
| regencySelect.addEventListener('change', async () => { | |
| const provinceId = provinceSelect.value; | |
| const regencyId = regencySelect.value; | |
| resetSelects(districtSelect, villageSelect); | |
| if (regencyId) { | |
| const districts = await fetchData(`/api/provinces/${provinceId}/regencies/${regencyId}/districts`); | |
| populateSelect(districtSelect, districts, 'Pilih Kecamatan'); | |
| districtSelect.disabled = false; | |
| } | |
| }); | |
| districtSelect.addEventListener('change', async () => { | |
| const provinceId = provinceSelect.value; | |
| const regencyId = regencySelect.value; | |
| const districtId = districtSelect.value; | |
| resetSelects(villageSelect); | |
| if (districtId) { | |
| const villages = await fetchData(`/api/provinces/${provinceId}/regencies/${regencyId}/districts/${districtId}/villages`); | |
| populateSelect(villageSelect, villages, 'Pilih Desa/Kelurahan'); | |
| villageSelect.disabled = false; | |
| } | |
| }); | |
| searchButton.addEventListener('click', () => { | |
| if (!provinceSelect.value || !regencySelect.value || !districtSelect.value || !villageSelect.value || !nameInput.value.trim()) { | |
| alert('Mohon lengkapi semua data wilayah dan nama sebelum melanjutkan.'); | |
| return; | |
| } | |
| document.getElementById('r-nama').textContent = nameInput.value.trim().toUpperCase(); | |
| document.getElementById('r-prov').textContent = provinceSelect.options[provinceSelect.selectedIndex].text; | |
| document.getElementById('r-kab').textContent = regencySelect.options[regencySelect.selectedIndex].text; | |
| document.getElementById('r-kec').textContent = districtSelect.options[districtSelect.selectedIndex].text; | |
| document.getElementById('r-desa').textContent = villageSelect.options[villageSelect.selectedIndex].text; | |
| resultBox.style.display = 'block'; | |
| resultBox.scrollIntoView({ behavior: 'smooth', block: 'center' }); | |
| }); | |
| resetButton.addEventListener('click', () => { | |
| provinceSelect.selectedIndex = 0; | |
| nameInput.value = ''; | |
| resetSelects(regencySelect, districtSelect, villageSelect); | |
| resultBox.style.display = 'none'; | |
| }); | |
| copyButton.addEventListener('click', () => { | |
| const summaryText = `RINGKASAN DATA SAYA:\nNama: ${document.getElementById('r-nama').textContent}\nProvinsi: ${document.getElementById('r-prov').textContent}\nKab/Kota: ${document.getElementById('r-kab').textContent}\nKecamatan: ${document.getElementById('r-kec').textContent}\nDesa/Kel: ${document.getElementById('r-desa').textContent}`; | |
| navigator.clipboard.writeText(summaryText).then(() => { | |
| const copyTextSpan = document.getElementById('copy-text'); | |
| copyTextSpan.textContent = "Berhasil Disalin! \u2713"; | |
| setTimeout(() => { copyTextSpan.textContent = "Salin Ringkasan"; }, 2000); | |
| }).catch(err => { | |
| console.error('Gagal menyalin: ', err); | |
| alert('Gagal menyalin data secara otomatis.'); | |
| }); | |
| }); | |
| }); | |
| function sendHeight() { | |
| if (window.parent) { | |
| const height = document.body.scrollHeight; | |
| window.parent.postMessage( | |
| { | |
| height: height, | |
| }, | |
| "*" | |
| ); | |
| } | |
| } | |
| // --- Logic for Embedding and Dynamic Resizing --- | |
| document.addEventListener("DOMContentLoaded", () => { | |
| // Initial animations on page load | |
| document.querySelectorAll(".animate__animated").forEach((el, i) => { | |
| el.style.animationDelay = `${i * 0.1}s`; | |
| }); | |
| // Send initial height to parent window | |
| sendHeight(); | |
| // Use a MutationObserver to watch for any changes in the page content | |
| // and send the new height to the parent window. | |
| const observer = new MutationObserver(() => sendHeight()); | |
| observer.observe(document.body, { | |
| childList: true, | |
| subtree: true, | |
| attributes: true, | |
| characterData: true, | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |