Update Alert Profil Petani
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
{{--
|
||||
Ringkasan isian WAJIB (skor) dan PERLU (dashboard) yang belum terisi di tab petani yang sedang dibuka.
|
||||
Daftar isiannya ada di App\Services\Produktivitas\KelengkapanPetani.
|
||||
Klik isian → halaman menggulir ke kolomnya (dicari lewat atribut name).
|
||||
--}}
|
||||
@props(['petani', 'lahan' => null])
|
||||
|
||||
@use('App\Services\Produktivitas\KelengkapanPetani')
|
||||
|
||||
@php
|
||||
$tab = match (true) {
|
||||
request()->routeIs('petani.edit') => 'profil',
|
||||
request()->routeIs('petani.lahan-tanaman.*') => 'lahan',
|
||||
request()->routeIs('petani.praktik-budidaya.*') => 'praktik-budidaya',
|
||||
request()->routeIs('petani.sosial-ekonomi.*') => 'sosial-ekonomi',
|
||||
request()->routeIs('petani.akses-pasar.*') => 'akses-pasar',
|
||||
request()->routeIs('petani.skor.*') => 'semua',
|
||||
default => null,
|
||||
};
|
||||
|
||||
$urlTab = fn (string $t) => $t === 'profil'
|
||||
? route('petani.edit', $petani->id)
|
||||
: route('petani.' . ($t === 'lahan' ? 'lahan-tanaman' : $t) . '.index', $petani->id);
|
||||
|
||||
$kelengkapan = $tab ? KelengkapanPetani::untuk($petani) : null;
|
||||
|
||||
if ($tab === 'semua') {
|
||||
// Tab Kesiapan Adopsi: rangkuman semua tab, klik → pindah ke tab terkait.
|
||||
$kelompok = $kelengkapan->semuaKosong()
|
||||
->map(fn ($items, $t) => $items->map(fn ($item) => [
|
||||
...$item,
|
||||
'url' => ($item['url'] ?? $urlTab($t)) . ($item['input'] ? '#isian=' . $item['input'] : ''),
|
||||
]))
|
||||
->filter(fn ($items) => $items->isNotEmpty())
|
||||
->mapWithKeys(fn ($items, $t) => [KelengkapanPetani::TAB_LABEL[$t] => $items]);
|
||||
} elseif ($tab) {
|
||||
// Di halaman edit lahan, isian lahan yang sedang dibuka langsung digulir (tanpa pindah halaman).
|
||||
$lahanDibukaId = $tab === 'lahan' && request()->routeIs('petani.lahan-tanaman.edit') ? $lahan?->id : null;
|
||||
|
||||
$kelompok = $kelengkapan->kosong($tab)
|
||||
->map(function ($item) use ($lahanDibukaId) {
|
||||
$dibuka = $lahanDibukaId && $item['lahan_id'] === $lahanDibukaId;
|
||||
|
||||
return [
|
||||
...$item,
|
||||
'grup' => $dibuka ? $item['grup'] . ' (sedang dibuka)' : $item['grup'],
|
||||
'url' => ($dibuka || ! $item['url']) ? null : $item['url'] . ($item['input'] ? '#isian=' . $item['input'] : ''),
|
||||
];
|
||||
})
|
||||
->groupBy(fn ($item) => $item['grup'] ?? '');
|
||||
}
|
||||
|
||||
$semuaItem = $tab ? $kelompok->flatten(1) : collect();
|
||||
$jumlahWajib = $semuaItem->where('prioritas', KelengkapanPetani::WAJIB)->count();
|
||||
$jumlahPerlu = $semuaItem->where('prioritas', KelengkapanPetani::PERLU)->count();
|
||||
@endphp
|
||||
|
||||
@if ($tab)
|
||||
@if ($semuaItem->isEmpty())
|
||||
<div class="alert alert-success d-flex align-items-center py-2 mb-6" role="alert">
|
||||
<i class="icon-base ti tabler-circle-check me-2"></i>
|
||||
{{ $tab === 'semua' ? 'Semua isian wajib dan perlu sudah terisi.' : 'Semua isian wajib dan perlu di tab ini sudah terisi.' }}
|
||||
</div>
|
||||
@else
|
||||
{{-- Klik di mana saja pada kartu untuk membuka/menutup detail (kecuali tombol isian). --}}
|
||||
<div class="card mb-6 border border-warning kartu-kelengkapan" id="kelengkapan-petani"
|
||||
role="button" aria-expanded="false" aria-controls="kelengkapan-petani-detail" title="Klik untuk menampilkan/menyembunyikan detail">
|
||||
<div class="card-body py-3">
|
||||
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="icon-base ti tabler-alert-triangle text-warning me-2"></i>
|
||||
<span class="fw-medium">
|
||||
Belum terisi{{ $tab === 'semua' ? '' : ' di tab ini' }}:
|
||||
@if ($jumlahWajib)
|
||||
<span class="badge bg-label-danger ms-1">{{ $jumlahWajib }} wajib</span>
|
||||
@endif
|
||||
@if ($jumlahPerlu)
|
||||
<span class="badge bg-label-warning ms-1">{{ $jumlahPerlu }} perlu</span>
|
||||
@endif
|
||||
</span>
|
||||
</div>
|
||||
<span class="btn btn-sm btn-icon btn-text-secondary rounded-pill ikon-toggle-kelengkapan" aria-hidden="true">
|
||||
<i class="icon-base ti tabler-chevron-down"></i>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="collapse" id="kelengkapan-petani-detail">
|
||||
<small class="text-muted d-block mt-2">
|
||||
<span class="badge badge-dot bg-danger me-1"></span>Wajib: dipakai skor Kesiapan Adopsi
|
||||
<span class="badge badge-dot bg-warning ms-3 me-1"></span>Perlu: dipakai dashboard.
|
||||
Klik isian untuk menuju kolomnya.
|
||||
</small>
|
||||
|
||||
@foreach ($kelompok as $judul => $items)
|
||||
<div class="mt-3">
|
||||
@if ($judul !== '')
|
||||
<div class="small fw-medium mb-1">{{ $judul }}</div>
|
||||
@endif
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
@foreach ($items->sortBy(fn ($i) => $i['prioritas'] === KelengkapanPetani::WAJIB ? 0 : 1) as $item)
|
||||
<button type="button"
|
||||
class="btn btn-xs btn-isian-kosong {{ $item['prioritas'] === KelengkapanPetani::WAJIB ? 'btn-label-danger' : 'btn-label-warning' }}"
|
||||
data-input="{{ $item['input'] }}"
|
||||
data-url="{{ $item['url'] }}">
|
||||
{{ $item['label'] }}
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@once
|
||||
@push('style')
|
||||
<style>
|
||||
.kartu-kelengkapan { cursor: pointer; }
|
||||
.kartu-kelengkapan .btn-isian-kosong { cursor: pointer; }
|
||||
.ikon-toggle-kelengkapan i { transition: transform .2s; }
|
||||
.kartu-kelengkapan.terbuka .ikon-toggle-kelengkapan i { transform: rotate(180deg); }
|
||||
.isian-disorot {
|
||||
outline: 2px solid var(--bs-warning);
|
||||
outline-offset: 4px;
|
||||
border-radius: .375rem;
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
(function () {
|
||||
function cariKolom(name) {
|
||||
if (!name) return null;
|
||||
const el = document.querySelector(`[name="${name}"], [name="${name}[]"], [name^="${name}["]`);
|
||||
if (!el) return null;
|
||||
|
||||
// Kolom tersembunyi (mis. radio custom/select2): sorot pembungkus terdekat yang terlihat.
|
||||
let target = el.closest('.col-md-12, .col-md-6, .col-md-4, .col-12, .col, .mb-4, .mb-6') || el;
|
||||
while (target && target.offsetParent === null && target.parentElement) {
|
||||
target = target.parentElement;
|
||||
}
|
||||
return { el, target };
|
||||
}
|
||||
|
||||
function sorot(name) {
|
||||
const hasil = cariKolom(name);
|
||||
if (!hasil) return false;
|
||||
|
||||
hasil.target.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
hasil.target.classList.add('isian-disorot');
|
||||
setTimeout(() => hasil.target.classList.remove('isian-disorot'), 2500);
|
||||
if (hasil.el.offsetParent !== null && typeof hasil.el.focus === 'function') {
|
||||
hasil.el.focus({ preventScroll: true });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Buka/tutup detail dengan klik di mana saja pada kartu.
|
||||
const kartu = document.getElementById('kelengkapan-petani');
|
||||
const detail = document.getElementById('kelengkapan-petani-detail');
|
||||
if (kartu && detail) {
|
||||
kartu.addEventListener('click', function (e) {
|
||||
if (e.target.closest('.btn-isian-kosong')) return;
|
||||
if (window.getSelection().toString()) return; // sedang menyeleksi teks
|
||||
bootstrap.Collapse.getOrCreateInstance(detail, { toggle: false }).toggle();
|
||||
});
|
||||
detail.addEventListener('show.bs.collapse', () => { kartu.classList.add('terbuka'); kartu.setAttribute('aria-expanded', 'true'); });
|
||||
detail.addEventListener('hide.bs.collapse', () => { kartu.classList.remove('terbuka'); kartu.setAttribute('aria-expanded', 'false'); });
|
||||
}
|
||||
|
||||
document.addEventListener('click', function (e) {
|
||||
const btn = e.target.closest('.btn-isian-kosong');
|
||||
if (!btn) return;
|
||||
|
||||
if (btn.dataset.url) {
|
||||
window.location.href = btn.dataset.url;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sorot(btn.dataset.input)) {
|
||||
const pesan = 'Kolom ini belum tampil di halaman ini. Simpan bagian yang sudah ada terlebih dahulu, atau periksa jawaban pertanyaan sebelumnya.';
|
||||
window.Swal ? Swal.fire({ icon: 'info', text: pesan }) : alert(pesan);
|
||||
}
|
||||
});
|
||||
|
||||
// Datang dari tab lain dengan #isian=nama_kolom
|
||||
window.addEventListener('load', function () {
|
||||
const cocok = window.location.hash.match(/^#isian=(.+)$/);
|
||||
if (cocok) setTimeout(() => sorot(decodeURIComponent(cocok[1])), 300);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@endpush
|
||||
@endonce
|
||||
@endif
|
||||
Reference in New Issue
Block a user