Update Monitoring dan Verifikasi Petani
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
{{--
|
||||
Data petani Terverifikasi: halaman hanya untuk dilihat.
|
||||
Semua tombol simpan/tambah/hapus dan isian form dinonaktifkan (server juga menolak, lihat BatasiAksesPetani).
|
||||
--}}
|
||||
<div class="alert alert-success d-flex align-items-center mb-6" role="alert">
|
||||
<span class="alert-icon rounded me-3"><i class="icon-base ti tabler-lock"></i></span>
|
||||
<span>Data petani ini sudah <strong>terverifikasi</strong> dan hanya bisa dilihat. Data tidak dapat diubah, ditambah, atau dihapus.</span>
|
||||
</div>
|
||||
|
||||
@once
|
||||
@push('style')
|
||||
<style>
|
||||
/* Area unggah/hapus foto (dropzone) & elemen yang dikunci tidak bisa diklik. */
|
||||
.data-terkunci .dz-btn-action, .data-terkunci .btn-tambah-foto, .data-terkunci .dropzone,
|
||||
.kunci-terverifikasi { pointer-events: none !important; opacity: .65; }
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
(function () {
|
||||
const area = document.querySelector('.content-wrapper');
|
||||
if (!area) return;
|
||||
area.classList.add('data-terkunci');
|
||||
|
||||
// Tombol hapus/tambah yang bukan bagian form (dijalankan lewat JS/AJAX) & tautan ke halaman tambah.
|
||||
const TOMBOL_UBAH = [
|
||||
'[class*="delete"]', '[class*="hapus"]', '.btn-danger', '.btn-outline-danger',
|
||||
'.btn-tambah-foto', '.dz-btn-action', '.add-new', 'a[href$="/create"]',
|
||||
].join(',');
|
||||
|
||||
// Bagian yang tetap aktif: tab, ringkasan kelengkapan, pencarian/filter (form GET).
|
||||
const dikecualikan = (el) => el.closest('.nav, #kelengkapan-petani, form[method="GET" i], form:not([method])');
|
||||
|
||||
function kunci() {
|
||||
// Semua isian & tombol di form yang menyimpan data (POST/PUT/DELETE).
|
||||
area.querySelectorAll('form[method="POST" i]').forEach((form) => {
|
||||
form.querySelectorAll('input:not([type="hidden"]), select, textarea, button').forEach((el) => {
|
||||
el.disabled = true;
|
||||
});
|
||||
form.addEventListener('submit', (e) => e.preventDefault());
|
||||
});
|
||||
|
||||
area.querySelectorAll(TOMBOL_UBAH).forEach((el) => {
|
||||
if (dikecualikan(el)) return;
|
||||
el.classList.add('kunci-terverifikasi');
|
||||
el.setAttribute('aria-disabled', 'true');
|
||||
el.setAttribute('tabindex', '-1');
|
||||
if ('disabled' in el) el.disabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Setelah plugin (select2, flatpickr, dropzone, repeater) selesai dipasang.
|
||||
window.addEventListener('load', () => { kunci(); setTimeout(kunci, 500); });
|
||||
})();
|
||||
</script>
|
||||
@endpush
|
||||
@endonce
|
||||
@@ -112,13 +112,19 @@
|
||||
...gayaTombolSwal(),
|
||||
};
|
||||
|
||||
// Tandai Lengkap: wajib mencentang pernyataan sebelum bisa lanjut.
|
||||
// Tandai Lengkap: tampilkan pernyataan; menekan tombol konfirmasi berarti menyetujuinya.
|
||||
if (pernyataan) {
|
||||
opsi.input = 'checkbox';
|
||||
opsi.inputValue = 0;
|
||||
opsi.inputPlaceholder = pernyataan;
|
||||
opsi.inputValidator = (dicentang) => !dicentang && 'Centang pernyataan terlebih dahulu.';
|
||||
opsi.customClass.input = 'text-start small';
|
||||
const isi = document.createElement('div');
|
||||
const kotak = document.createElement('div');
|
||||
kotak.className = 'border rounded p-3 mb-3 text-start small';
|
||||
kotak.textContent = pernyataan;
|
||||
const catatan = document.createElement('p');
|
||||
catatan.className = 'mb-0';
|
||||
catatan.textContent = form.dataset.konfirmasi;
|
||||
isi.append(kotak, catatan);
|
||||
|
||||
delete opsi.text;
|
||||
opsi.html = isi;
|
||||
}
|
||||
|
||||
Swal.fire(opsi).then((r) => { if (r.isConfirmed) kirim(); });
|
||||
|
||||
@@ -125,6 +125,24 @@
|
||||
@endif
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
{{-- Menu Verifikasi: hanya super_admin, admin, koordinator (enumerator tidak). --}}
|
||||
@if($isAdmin || $isKoordinator)
|
||||
<li class="menu-item {{ request()->routeIs('monitoring-verifikasi.*') ? 'active open' : '' }}">
|
||||
<a href="javascript:void(0);" class="menu-link menu-toggle">
|
||||
<span class="menu-icon sidebar-icon" aria-hidden="true"><i class="icon-base ti tabler-rosette-discount-check"></i></span>
|
||||
<div data-i18n="Verifikasi">Verifikasi</div>
|
||||
</a>
|
||||
<ul class="menu-sub">
|
||||
<li class="menu-item {{ request()->routeIs('monitoring-verifikasi.petani.*') ? 'active' : '' }}">
|
||||
<a href="{{ route('monitoring-verifikasi.petani.monitoring') }}" class="menu-link">
|
||||
<span class="menu-icon sidebar-icon" aria-hidden="true"><i class="icon-base ti tabler-user-circle"></i></span>
|
||||
<div data-i18n="Petani">Petani</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if($isAdmin && $appName === 'AgroPro')
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
@use('App\Services\Produktivitas\KelengkapanPetani')
|
||||
|
||||
@if (($bagian ?? 'tabel') === 'rincian')
|
||||
{{-- ============ Isi kartu rincian: petani yang diinput enumerator ini ============ --}}
|
||||
<div class="d-flex align-items-center mb-6">
|
||||
<div class="avatar avatar-md me-3 flex-shrink-0">
|
||||
<span class="avatar-initial rounded bg-label-primary">{{ Str::upper(Str::substr($user->name, 0, 2)) }}</span>
|
||||
</div>
|
||||
<div style="min-width: 0;">
|
||||
<h6 class="mb-0 text-truncate">{{ $user->name }}</h6>
|
||||
<small class="d-block text-body-secondary">{{ $daftarPetani->count() }} petani diinput</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-sm table-hover mb-0">
|
||||
<thead class="border-top">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama Petani</th>
|
||||
<th class="text-center" title="Pertanyaan skor Kesiapan Adopsi">Skor</th>
|
||||
<th class="text-center" title="Isian yang dipakai dashboard">Wajib</th>
|
||||
<th class="text-center" title="Isian lainnya">Lainnya</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($daftarPetani as $item)
|
||||
@php $r = $ringkasan[$item->id]; @endphp
|
||||
<tr>
|
||||
<td>{{ $loop->iteration }}</td>
|
||||
<td class="text-wrap">
|
||||
<a href="{{ route('petani.edit', $item->id) }}" class="text-heading fw-medium">{{ $item->nama }}</a>
|
||||
<small class="d-block text-body-secondary">{{ $item->komoditas?->nama ?? '-' }}</small>
|
||||
</td>
|
||||
@foreach (['skor', 'wajib', 'lainnya'] as $jenis)
|
||||
<td class="text-center">
|
||||
<span class="badge bg-label-{{ KelengkapanPetani::warna($r[$jenis]) }}">{{ $r[$jenis]['terisi'] }}/{{ $r[$jenis]['total'] }}</span>
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="5" class="text-center py-4">Belum ada petani.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
{{-- ============ Tabel enumerator; klik jumlah petani → kartu rincian ============ --}}
|
||||
<div class="monitoring-split">
|
||||
<div class="kolom-tabel">
|
||||
<form method="GET" action="{{ route('monitoring-verifikasi.petani.monitoring') }}" class="d-flex justify-content-between align-items-center row gap-3 gap-md-0 mb-4">
|
||||
<input type="hidden" name="sub" value="enumerator">
|
||||
<div class="col-md-auto">
|
||||
<div class="d-flex align-items-center">
|
||||
<label class="me-2 text-nowrap">Show</label>
|
||||
<select name="per_page_enumerator" class="form-select form-select-sm w-auto" onchange="this.form.submit()">
|
||||
@foreach ($perPage as $n)
|
||||
<option value="{{ $n }}" @selected($enumerator->perPage() == $n)>{{ $n }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<label class="ms-2 text-nowrap">entries</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-auto">
|
||||
<div class="input-group input-group-sm w-auto">
|
||||
<input type="text" name="search_enumerator" class="form-control" placeholder="Cari nama enumerator..." value="{{ request('search_enumerator') }}">
|
||||
<button type="submit" class="btn btn-outline-primary"><i class="icon-base ti tabler-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-hover">
|
||||
<thead class="border-top">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Enumerator</th>
|
||||
<th class="text-center">Jumlah Petani</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($enumerator as $index => $user)
|
||||
<tr>
|
||||
<td>{{ $enumerator->firstItem() + $index }}</td>
|
||||
<td>
|
||||
<span class="text-heading fw-medium d-block">{{ $user->name }}</span>
|
||||
<small class="text-body-secondary">{{ $user->email }}</small>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
@if ($user->jumlah_petani > 0)
|
||||
<button type="button" class="btn btn-sm btn-label-primary btn-buka-rincian"
|
||||
data-url="{{ route('monitoring-verifikasi.petani.monitoring.enumerator', $user->id) }}"
|
||||
data-judul="Petani oleh {{ $user->name }}" title="Lihat petani yang diinput">
|
||||
{{ $user->jumlah_petani }} petani
|
||||
</button>
|
||||
@else
|
||||
<span class="badge bg-label-secondary">0 petani</span>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="3" class="text-center py-4">Tidak ada data ditemukan.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-center justify-content-md-end border-top pt-4">
|
||||
{{ $enumerator->links('pagination::bootstrap-5') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kolom-detail" aria-hidden="true"></div>
|
||||
</div>
|
||||
@endif
|
||||
@@ -0,0 +1,195 @@
|
||||
@extends('layout.main')
|
||||
|
||||
@php
|
||||
$menu = $menu ?? 'petani';
|
||||
|
||||
$tabs = [
|
||||
'monitoring' => ['label' => 'Monitoring', 'ikon' => 'tabler-chart-dots'],
|
||||
'verifikasi' => ['label' => 'Verifikasi', 'ikon' => 'tabler-rosette-discount-check'],
|
||||
];
|
||||
@endphp
|
||||
|
||||
@section('content')
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
{{-- Vuexy: justified pills (nav-fill) → tiap tab sama lebar. --}}
|
||||
<div class="nav-align-top">
|
||||
<ul class="nav nav-pills nav-fill mb-6" role="tablist">
|
||||
@foreach ($tabs as $kunci => $tab)
|
||||
@php
|
||||
$namaRoute = "monitoring-verifikasi.{$menu}.{$kunci}";
|
||||
$tersedia = Route::has($namaRoute);
|
||||
$aktif = request()->routeIs($namaRoute . '*');
|
||||
@endphp
|
||||
<li class="nav-item">
|
||||
<a @class(['nav-link', 'active' => $aktif, 'disabled' => ! $tersedia])
|
||||
href="{{ $tersedia ? route($namaRoute) : 'javascript:void(0);' }}"
|
||||
@if ($aktif) aria-current="page" @endif
|
||||
@unless ($tersedia) aria-disabled="true" @endunless>
|
||||
<span class="d-none d-sm-inline-flex align-items-center">
|
||||
<i class="icon-base ti {{ $tab['ikon'] }} icon-sm me-1_5"></i>{{ $tab['label'] }}
|
||||
</span>
|
||||
<i class="icon-base ti {{ $tab['ikon'] }} icon-sm d-sm-none"></i>
|
||||
</a>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{{-- Sub-tab: halaman turunan cukup mendefinisikan $idSubTab & $subTabs (label, ikon, view, jumlah opsional). --}}
|
||||
@isset($subTabs)
|
||||
@php $subTabAktif = array_key_exists(request('sub'), $subTabs) ? request('sub') : array_key_first($subTabs); @endphp
|
||||
<div class="nav-align-top nav-tabs-shadow">
|
||||
<ul class="nav nav-tabs nav-fill" role="tablist">
|
||||
@foreach ($subTabs as $kunci => $tab)
|
||||
<li class="nav-item" role="presentation">
|
||||
<button type="button" role="tab"
|
||||
@class(['nav-link', 'active' => $kunci === $subTabAktif])
|
||||
data-bs-toggle="tab" data-bs-target="#{{ $idSubTab }}-{{ $kunci }}"
|
||||
aria-controls="{{ $idSubTab }}-{{ $kunci }}" aria-selected="{{ $kunci === $subTabAktif ? 'true' : 'false' }}">
|
||||
<span class="d-none d-sm-inline-flex align-items-center">
|
||||
<i class="icon-base ti {{ $tab['ikon'] }} icon-sm me-1_5"></i>{{ $tab['label'] }}
|
||||
@isset($tab['jumlah'])
|
||||
<span class="badge rounded-pill badge-center h-px-20 w-px-20 bg-label-primary ms-1_5">{{ $tab['jumlah'] }}</span>
|
||||
@endisset
|
||||
</span>
|
||||
<i class="icon-base ti {{ $tab['ikon'] }} icon-sm d-sm-none"></i>
|
||||
</button>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
@foreach ($subTabs as $kunci => $tab)
|
||||
<div @class(['tab-pane fade', 'show active' => $kunci === $subTabAktif]) id="{{ $idSubTab }}-{{ $kunci }}" role="tabpanel">
|
||||
@include($tab['view'])
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<span class="avatar avatar-md mx-auto mb-2">
|
||||
<span class="avatar-initial rounded bg-label-secondary"><i class="icon-base ti tabler-layout-dashboard icon-26px"></i></span>
|
||||
</span>
|
||||
<p class="mb-0 text-body-secondary">Konten tab belum dibuat.</p>
|
||||
</div>
|
||||
</div>
|
||||
@endisset
|
||||
|
||||
{{-- Kartu rincian: disalin otomatis ke setiap .kolom-detail yang masih kosong. --}}
|
||||
<template id="template-kartu-rincian">
|
||||
<div class="card shadow-none border h-100 kartu-rincian">
|
||||
<div class="card-header d-flex justify-content-between align-items-center border-bottom">
|
||||
<h5 class="card-title mb-0 kartu-rincian-judul">Rincian</h5>
|
||||
<button type="button" class="btn-close btn-tutup-rincian" aria-label="Tutup"></button>
|
||||
</div>
|
||||
<div class="card-body pt-6 kartu-rincian-isi"></div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('style')
|
||||
<style>
|
||||
/* Tabel penuh; saat rincian dibuka, tabel menyusut & kartu rincian bergeser masuk dari kanan. */
|
||||
.monitoring-split { display: flex; gap: 0; transition: gap .3s ease; }
|
||||
.monitoring-split .kolom-tabel { flex: 1 1 100%; min-width: 0; transition: flex-basis .3s ease; }
|
||||
.monitoring-split .kolom-detail {
|
||||
flex: 0 0 0; max-width: 0; min-width: 0; opacity: 0; overflow: hidden;
|
||||
transform: translateX(1.5rem);
|
||||
transition: flex-basis .3s ease, max-width .3s ease, opacity .3s ease, transform .3s ease;
|
||||
}
|
||||
.monitoring-split.terbuka { gap: 1.5rem; }
|
||||
.monitoring-split.terbuka .kolom-tabel { flex-basis: 58%; }
|
||||
.monitoring-split.terbuka .kolom-detail { flex-basis: 42%; max-width: 42%; opacity: 1; transform: none; }
|
||||
|
||||
/* Kartu rincian ikut terlihat saat halaman digulir; isinya bisa digulir sendiri. */
|
||||
.kartu-rincian { position: sticky; top: 1rem; max-height: calc(100vh - 2rem); }
|
||||
.kartu-rincian .card-body { overflow-y: auto; }
|
||||
|
||||
/* Baris tabel yang bisa diklik untuk membuka rincian. */
|
||||
tr.btn-buka-rincian { cursor: pointer; }
|
||||
|
||||
/* Layar kecil: rincian tampil di bawah tabel. */
|
||||
@media (max-width: 991.98px) {
|
||||
.monitoring-split { flex-direction: column; }
|
||||
.monitoring-split.terbuka .kolom-tabel,
|
||||
.monitoring-split.terbuka .kolom-detail { flex-basis: auto; max-width: 100%; }
|
||||
.kartu-rincian { position: static; max-height: none; }
|
||||
}
|
||||
</style>
|
||||
@endpush
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
(function () {
|
||||
const memuat = '<div class="text-center py-6"><div class="spinner-border text-primary" role="status"></div></div>';
|
||||
const layarKecil = () => window.matchMedia('(max-width: 991.98px)').matches;
|
||||
const templateKartu = document.getElementById('template-kartu-rincian');
|
||||
|
||||
document.querySelectorAll('.monitoring-split').forEach(function (split) {
|
||||
const kolomTabel = split.querySelector('.kolom-tabel');
|
||||
const kolomDetail = split.querySelector('.kolom-detail');
|
||||
if (!kolomDetail.children.length) kolomDetail.append(templateKartu.content.cloneNode(true));
|
||||
const judul = kolomDetail.querySelector('.kartu-rincian-judul');
|
||||
const isi = kolomDetail.querySelector('.kartu-rincian-isi');
|
||||
let permintaan = 0; // abaikan respons lama kalau tombol lain sudah diklik
|
||||
let tombolAktif = null;
|
||||
|
||||
const tandai = (tombol) => {
|
||||
kolomTabel.querySelectorAll('tr.table-active').forEach((tr) => tr.classList.remove('table-active'));
|
||||
tombol?.closest('tr')?.classList.add('table-active');
|
||||
tombolAktif = tombol;
|
||||
};
|
||||
|
||||
const tutup = () => {
|
||||
split.classList.remove('terbuka');
|
||||
kolomDetail.setAttribute('aria-hidden', 'true');
|
||||
tandai(null);
|
||||
permintaan++;
|
||||
};
|
||||
split.tutupRincian = tutup;
|
||||
|
||||
kolomDetail.querySelector('.btn-tutup-rincian').addEventListener('click', tutup);
|
||||
|
||||
kolomTabel.addEventListener('click', async function (e) {
|
||||
const tombol = e.target.closest('.btn-buka-rincian');
|
||||
if (!tombol) return;
|
||||
// Tautan di dalam baris yang bisa diklik tetap berfungsi sebagai tautan.
|
||||
const tautan = e.target.closest('a');
|
||||
if (tautan && tautan !== tombol && tombol.contains(tautan)) return;
|
||||
|
||||
// Klik tombol yang sama lagi → tutup.
|
||||
if (tombol === tombolAktif && split.classList.contains('terbuka')) return tutup();
|
||||
|
||||
const nomor = ++permintaan;
|
||||
tandai(tombol);
|
||||
judul.textContent = tombol.dataset.judul || 'Rincian';
|
||||
isi.innerHTML = memuat;
|
||||
isi.scrollTop = 0;
|
||||
split.classList.add('terbuka');
|
||||
kolomDetail.setAttribute('aria-hidden', 'false');
|
||||
if (layarKecil()) kolomDetail.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
|
||||
try {
|
||||
const res = await fetch(tombol.dataset.url, { headers: { 'X-Requested-With': 'XMLHttpRequest' } });
|
||||
if (!res.ok) throw new Error(res.status);
|
||||
const html = await res.text();
|
||||
if (nomor === permintaan) isi.innerHTML = html;
|
||||
} catch (err) {
|
||||
if (nomor === permintaan) {
|
||||
isi.innerHTML = '<div class="alert alert-danger mb-0">Gagal memuat rincian. Coba lagi.</div>';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Esc menutup rincian yang sedang terbuka.
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key !== 'Escape') return;
|
||||
document.querySelectorAll('.monitoring-split.terbuka').forEach((split) => split.tutupRincian?.());
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,9 @@
|
||||
@extends('monitoring-verifikasi.index')
|
||||
|
||||
@php
|
||||
$idSubTab = 'monitoring';
|
||||
$subTabs = [
|
||||
'petani' => ['label' => 'Petani', 'ikon' => 'tabler-user-circle', 'view' => 'monitoring-verifikasi.petani-monitoring'],
|
||||
'enumerator' => ['label' => 'Enumerator', 'ikon' => 'tabler-clipboard-list', 'view' => 'monitoring-verifikasi.enumerator'],
|
||||
];
|
||||
@endphp
|
||||
@@ -0,0 +1,182 @@
|
||||
@use('App\Services\Produktivitas\KelengkapanPetani')
|
||||
|
||||
@php
|
||||
$langkah = [
|
||||
1 => ['jenis' => 'skor', 'label' => 'Input Skor'],
|
||||
2 => ['jenis' => 'wajib', 'label' => 'Input Wajib'],
|
||||
3 => ['jenis' => 'lainnya', 'label' => 'Input Lainnya'],
|
||||
];
|
||||
@endphp
|
||||
|
||||
@if (($bagian ?? 'tabel') === 'rincian')
|
||||
{{-- ============ Isi kartu verifikasi: profil + 3 langkah pemeriksaan ============ --}}
|
||||
@php $skorIndeks = $petani->skor?->skor_kesiapan_adopsi; @endphp
|
||||
|
||||
<div class="stepper-verifikasi">
|
||||
@include('monitoring-verifikasi.petani-monitoring', ['bagian' => 'profil'])
|
||||
|
||||
<div class="row g-4 mb-6">
|
||||
<div class="col-6">
|
||||
<label class="form-label">Enumerator</label>
|
||||
<input type="text" class="form-control" readonly value="{{ $petani->creator?->name ?? '-' }}">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label">Skor Indeks</label>
|
||||
<input type="text" class="form-control" readonly
|
||||
value="{{ is_null($skorIndeks) ? '-' : number_format($skorIndeks, 1, ',', '.') . '/5 · ' . $petani->segmen() }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($petani->catatan)
|
||||
{{-- Catatan saat terakhir dikembalikan ke Draf --}}
|
||||
<div class="alert alert-warning mb-6" role="alert">
|
||||
<h6 class="alert-heading mb-1">Catatan sebelumnya</h6>
|
||||
<p class="mb-0" style="white-space: pre-line;">{{ $petani->catatan }}</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Penanda langkah --}}
|
||||
<div class="d-flex justify-content-between gap-2 border-bottom pb-4 mb-6">
|
||||
@foreach ($langkah as $n => $l)
|
||||
@php $hitung = $ringkasan[$l['jenis']]; @endphp
|
||||
<div class="d-flex align-items-center gap-2 langkah-item" data-langkah="{{ $n }}">
|
||||
<span class="avatar avatar-sm flex-shrink-0">
|
||||
<span @class(['avatar-initial rounded-circle langkah-nomor', 'bg-primary text-white' => $n === 1, 'bg-label-secondary' => $n !== 1])>{{ $n }}</span>
|
||||
</span>
|
||||
<span class="lh-sm">
|
||||
<span class="d-block fw-medium small text-heading">{{ $l['label'] }}</span>
|
||||
<small class="text-body-secondary">{{ $hitung['terisi'] }}/{{ $hitung['total'] }}</small>
|
||||
</span>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
{{-- Isi tiap langkah: periksa semua isian, lalu klik tombol di bawah --}}
|
||||
@foreach ($langkah as $n => $l)
|
||||
<form class="pt-0 langkah-pane {{ $n === 1 ? '' : 'd-none' }}" data-langkah="{{ $n }}" onsubmit="return false;">
|
||||
@include('monitoring-verifikasi.petani-monitoring', ['bagian' => 'isian', 'rincian' => $rincian[$l['jenis']]])
|
||||
|
||||
{{-- Langkah terakhir punya tombolnya sendiri di bawah --}}
|
||||
@if ($n < count($langkah))
|
||||
<div class="d-flex gap-2">
|
||||
@if ($n > 1)
|
||||
<button type="button" class="btn btn-label-secondary" data-ke-langkah="{{ $n - 1 }}">
|
||||
<i class="icon-base ti tabler-arrow-left icon-sm me-1"></i>Kembali
|
||||
</button>
|
||||
@endif
|
||||
<button type="button" class="btn btn-primary flex-grow-1" data-ke-langkah="{{ $n + 1 }}">
|
||||
Lengkap<i class="icon-base ti tabler-arrow-right icon-sm ms-1"></i>
|
||||
</button>
|
||||
</div>
|
||||
@endif
|
||||
</form>
|
||||
@endforeach
|
||||
|
||||
{{-- Langkah terakhir: Belum Lengkap (kembali ke Draf + catatan) atau Lengkap & Verifikasi --}}
|
||||
{{-- Baris 1: Kembali | Belum Lengkap (sama lebar). Baris 2: Lengkap & Verifikasi (penuh). --}}
|
||||
<div class="langkah-pane d-none" data-langkah="{{ count($langkah) }}">
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-6">
|
||||
<button type="button" class="btn btn-label-secondary w-100" data-ke-langkah="{{ count($langkah) - 1 }}">
|
||||
<i class="icon-base ti tabler-arrow-left icon-sm me-1"></i>Kembali
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<form method="POST" action="{{ route('monitoring-verifikasi.petani.verifikasi.kembalikan-draf', $petani->id) }}"
|
||||
class="form-kembalikan-draf" data-nama="{{ $petani->nama }}"
|
||||
data-judul="Data Belum Lengkap" data-pesan="Tuliskan apa yang perlu dilengkapi atau diperbaiki oleh enumerator.">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<input type="hidden" name="catatan" value="">
|
||||
<button type="submit" class="btn btn-label-danger w-100">
|
||||
<i class="icon-base ti tabler-file-alert icon-sm me-1"></i>Belum Lengkap
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<form method="POST" action="{{ route('monitoring-verifikasi.petani.verifikasi.update', $petani->id) }}"
|
||||
class="form-verifikasi-petani" data-nama="{{ $petani->nama }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<button type="submit" class="btn btn-primary w-100">
|
||||
<i class="icon-base ti tabler-rosette-discount-check icon-sm me-1"></i>Lengkap & Verifikasi
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
{{-- ============ Tabel petani berstatus Lengkap; klik di mana saja pada baris → kartu verifikasi ============ --}}
|
||||
<div class="monitoring-split">
|
||||
<div class="kolom-tabel">
|
||||
<form method="GET" action="{{ route('monitoring-verifikasi.petani.verifikasi') }}" class="d-flex justify-content-between align-items-center row gap-3 gap-md-0 mb-4">
|
||||
<input type="hidden" name="sub" value="lengkap">
|
||||
<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()">
|
||||
@foreach ($perPage as $n)
|
||||
<option value="{{ $n }}" @selected($petaniLengkap->perPage() == $n)>{{ $n }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<label class="ms-2 text-nowrap">entries</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-auto">
|
||||
<div class="input-group input-group-sm w-auto">
|
||||
<input type="text" name="search" class="form-control" placeholder="Cari nama petani..." value="{{ request('search') }}">
|
||||
<button type="submit" class="btn btn-outline-primary"><i class="icon-base ti tabler-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-hover">
|
||||
<thead class="border-top">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama Petani</th>
|
||||
<th>Komoditas</th>
|
||||
<th>Enumerator</th>
|
||||
@foreach ($langkah as $l)
|
||||
<th class="text-center">{{ $l['label'] }}</th>
|
||||
@endforeach
|
||||
<th>Terakhir Diperbarui</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($petaniLengkap as $index => $item)
|
||||
@php $r = $ringkasan[$item->id]; @endphp
|
||||
<tr class="btn-buka-rincian"
|
||||
data-url="{{ route('monitoring-verifikasi.petani.verifikasi.show', $item->id) }}"
|
||||
data-judul="Verifikasi {{ $item->nama }}" title="Klik untuk memeriksa & memverifikasi">
|
||||
<td>{{ $petaniLengkap->firstItem() + $index }}</td>
|
||||
<td><span class="text-heading fw-medium">{{ $item->nama }}</span></td>
|
||||
<td>{{ $item->komoditas?->nama ?? '-' }}</td>
|
||||
<td><span class="text-body-secondary">{{ $item->creator?->name ?? '-' }}</span></td>
|
||||
@foreach ($langkah as $l)
|
||||
<td class="text-center">
|
||||
<span class="badge bg-label-{{ KelengkapanPetani::warna($r[$l['jenis']]) }}">{{ $r[$l['jenis']]['terisi'] }}/{{ $r[$l['jenis']]['total'] }}</span>
|
||||
</td>
|
||||
@endforeach
|
||||
<td>
|
||||
<span class="d-block">{{ $item->updated_at?->translatedFormat('d M Y') ?? '-' }}</span>
|
||||
<small class="text-body-secondary">{{ $item->updated_at?->format('H:i') }}</small>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="8" class="text-center py-4">Belum ada data petani yang ditandai lengkap.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-center justify-content-md-end border-top pt-4">
|
||||
{{ $petaniLengkap->links('pagination::bootstrap-5') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kolom-detail" aria-hidden="true"></div>
|
||||
</div>
|
||||
@endif
|
||||
@@ -0,0 +1,136 @@
|
||||
@use('App\Services\Produktivitas\KelengkapanPetani')
|
||||
|
||||
@if (($bagian ?? 'tabel') === 'profil')
|
||||
{{-- ============ Profil singkat petani (dipakai juga di kartu verifikasi) ============ --}}
|
||||
@php $desa = $petani->desaKelurahan; @endphp
|
||||
<div class="d-flex align-items-center mb-6">
|
||||
<div class="avatar avatar-xl me-3 flex-shrink-0">
|
||||
<img src="{{ $petani->foto ? route('petani.show-image', ['id' => $petani->id, 'field' => 'foto']) : asset('assets/img/avatars/3.jpg') }}"
|
||||
alt="Foto {{ $petani->nama }}" class="rounded" style="object-fit: cover;">
|
||||
</div>
|
||||
<div style="min-width: 0;">
|
||||
<h6 class="mb-0 text-truncate">{{ $petani->nama }}</h6>
|
||||
<small class="d-block text-body-secondary">{{ is_null($petani->umur) ? 'Umur belum diisi' : $petani->umur . ' tahun' }}</small>
|
||||
<small class="d-block text-body-secondary">
|
||||
{{ $desa ? collect([$desa->nama, $desa->kecamatan?->nama, $desa->kecamatan?->kabupatenKota?->nama])->filter()->implode(', ') : 'Desa belum diisi' }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
@elseif (($bagian ?? 'tabel') === 'isian')
|
||||
{{-- ============ Daftar pertanyaan -> jawaban (dipakai juga di kartu verifikasi) ============ --}}
|
||||
@forelse ($rincian as $grup => $baris)
|
||||
<h6 class="pb-2 border-bottom mb-4">{{ $grup }}</h6>
|
||||
@foreach ($baris as $r)
|
||||
@php $kosong = ! $r['terisi'] || $r['jawaban'] === null; @endphp
|
||||
<div class="mb-6">
|
||||
<label class="form-label">{{ $r['label'] }}</label>
|
||||
@if (! $kosong && mb_strlen($r['jawaban']) > 60)
|
||||
<textarea class="form-control" rows="2" readonly>{{ $r['jawaban'] }}</textarea>
|
||||
@else
|
||||
<input type="text" @class(['form-control', 'is-invalid' => $kosong]) readonly
|
||||
value="{{ $kosong ? 'Belum diisi' : $r['jawaban'] }}">
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
@empty
|
||||
<p class="text-center text-body-secondary mb-6">Tidak ada isian.</p>
|
||||
@endforelse
|
||||
@elseif (($bagian ?? 'tabel') === 'rincian')
|
||||
{{-- ============ Isi kartu rincian: profil singkat + pertanyaan -> jawaban ============ --}}
|
||||
@php $skorIndeks = $petani->skor?->skor_kesiapan_adopsi; @endphp
|
||||
|
||||
<form class="pt-0" onsubmit="return false;">
|
||||
@include('monitoring-verifikasi.petani-monitoring', ['bagian' => 'profil'])
|
||||
|
||||
<div class="row g-4 mb-6">
|
||||
<div class="col-6">
|
||||
<label class="form-label">Skor Indeks</label>
|
||||
<input type="text" class="form-control" readonly
|
||||
value="{{ is_null($skorIndeks) ? '-' : number_format($skorIndeks, 1, ',', '.') . '/5 · ' . $petani->segmen() }}">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label">Terisi</label>
|
||||
<input type="text" class="form-control" readonly
|
||||
value="{{ $ringkasan['terisi'] }}/{{ $ringkasan['total'] }} ({{ $ringkasan['total'] ? floor($ringkasan['terisi'] / $ringkasan['total'] * 100) : 0 }}%)">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@include('monitoring-verifikasi.petani-monitoring', ['bagian' => 'isian'])
|
||||
</form>
|
||||
@else
|
||||
{{-- ============ Tabel petani; klik badge Input → kartu rincian ============ --}}
|
||||
@php
|
||||
$judulInput = ['skor' => 'Input Skor', 'wajib' => 'Input Wajib', 'lainnya' => 'Input Lainnya'];
|
||||
@endphp
|
||||
|
||||
<div class="monitoring-split">
|
||||
<div class="kolom-tabel">
|
||||
<form method="GET" action="{{ route('monitoring-verifikasi.petani.monitoring') }}" class="d-flex justify-content-between align-items-center row gap-3 gap-md-0 mb-4">
|
||||
<input type="hidden" name="sub" value="petani">
|
||||
<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()">
|
||||
@foreach ($perPage as $n)
|
||||
<option value="{{ $n }}" @selected($petani->perPage() == $n)>{{ $n }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<label class="ms-2 text-nowrap">entries</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-auto">
|
||||
<div class="input-group input-group-sm w-auto">
|
||||
<input type="text" name="search" class="form-control" placeholder="Cari nama petani..." value="{{ request('search') }}">
|
||||
<button type="submit" class="btn btn-outline-primary"><i class="icon-base ti tabler-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-hover">
|
||||
<thead class="border-top">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama Petani</th>
|
||||
<th>Komoditas</th>
|
||||
<th>Enumerator</th>
|
||||
<th class="text-center" title="Pertanyaan yang dinilai di skor Kesiapan Adopsi">Input Skor</th>
|
||||
<th class="text-center" title="Isian yang dipakai dashboard">Input Wajib</th>
|
||||
<th class="text-center" title="Isian lainnya di Profil Petani">Input Lainnya</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($petani as $index => $item)
|
||||
@php $r = $ringkasan[$item->id]; @endphp
|
||||
<tr>
|
||||
<td>{{ $petani->firstItem() + $index }}</td>
|
||||
<td><a href="{{ route('petani.edit', $item->id) }}" class="text-heading fw-medium">{{ $item->nama }}</a></td>
|
||||
<td>{{ $item->komoditas?->nama ?? '-' }}</td>
|
||||
<td><span class="text-body-secondary">{{ $item->creator?->name ?? '-' }}</span></td>
|
||||
@foreach ($judulInput as $jenis => $judul)
|
||||
<td class="text-center">
|
||||
<button type="button" class="btn btn-sm btn-label-{{ KelengkapanPetani::warna($r[$jenis]) }} btn-buka-rincian"
|
||||
data-url="{{ route('monitoring-verifikasi.petani.monitoring.detail', [$item->id, $jenis]) }}"
|
||||
data-judul="Rincian {{ $judul }}" title="Lihat rincian {{ strtolower($judul) }}">
|
||||
{{ $r[$jenis]['terisi'] }}/{{ $r[$jenis]['total'] }}
|
||||
</button>
|
||||
</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="text-center py-4">Tidak ada data ditemukan.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-center justify-content-md-end border-top pt-4">
|
||||
{{ $petani->links('pagination::bootstrap-5') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kolom-detail" aria-hidden="true"></div>
|
||||
</div>
|
||||
@endif
|
||||
@@ -0,0 +1,112 @@
|
||||
@if (($bagian ?? 'tabel') === 'rincian')
|
||||
{{-- ============ Isi kartu: profil + siapa & kapan diverifikasi + Kembalikan ke Draf ============ --}}
|
||||
<form class="pt-0" onsubmit="return false;">
|
||||
@include('monitoring-verifikasi.petani-monitoring', ['bagian' => 'profil'])
|
||||
|
||||
<div class="mb-6">
|
||||
<label class="form-label">Komoditas</label>
|
||||
<input type="text" class="form-control" readonly value="{{ $petani->komoditas?->nama ?? '-' }}">
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
<label class="form-label">Enumerator</label>
|
||||
<input type="text" class="form-control" readonly value="{{ $petani->creator?->name ?? '-' }}">
|
||||
</div>
|
||||
{{-- Data terverifikasi dikunci, jadi updated_by / updated_at = yang & waktu memverifikasi --}}
|
||||
<div class="mb-6">
|
||||
<label class="form-label">Diverifikasi Oleh</label>
|
||||
<input type="text" class="form-control" readonly
|
||||
value="{{ $petani->updater?->name ?? '-' }}{{ $petani->updater?->role ? ' · ' . $petani->updater->role->label() : '' }}">
|
||||
</div>
|
||||
<div class="mb-6">
|
||||
<label class="form-label">Waktu Verifikasi</label>
|
||||
<input type="text" class="form-control" readonly value="{{ $petani->updated_at?->translatedFormat('d M Y, H:i') ?? '-' }}">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{{-- Ada temuan setelah diverifikasi: kembalikan ke Draf dengan catatan --}}
|
||||
<form method="POST" action="{{ route('monitoring-verifikasi.petani.verifikasi.kembalikan-draf', $petani->id) }}"
|
||||
class="form-kembalikan-draf" data-nama="{{ $petani->nama }}"
|
||||
data-judul="Kembalikan ke Draf" data-pesan="Data ini sudah terverifikasi. Tuliskan temuan yang perlu diperbaiki oleh enumerator.">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<input type="hidden" name="catatan" value="">
|
||||
<button type="submit" class="btn btn-label-danger w-100">
|
||||
<i class="icon-base ti tabler-arrow-back-up icon-sm me-1"></i>Kembalikan ke Draf
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
{{-- ============ Tabel petani terverifikasi; klik di mana saja pada baris → kartu rincian ============ --}}
|
||||
<div class="monitoring-split">
|
||||
<div class="kolom-tabel">
|
||||
<form method="GET" action="{{ route('monitoring-verifikasi.petani.verifikasi') }}" class="d-flex justify-content-between align-items-center row gap-3 gap-md-0 mb-4">
|
||||
<input type="hidden" name="sub" value="terverifikasi">
|
||||
<div class="col-md-auto">
|
||||
<div class="d-flex align-items-center">
|
||||
<label class="me-2 text-nowrap">Show</label>
|
||||
<select name="per_page_terverifikasi" class="form-select form-select-sm w-auto" onchange="this.form.submit()">
|
||||
@foreach ($perPage as $n)
|
||||
<option value="{{ $n }}" @selected($petaniTerverifikasi->perPage() == $n)>{{ $n }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<label class="ms-2 text-nowrap">entries</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-auto">
|
||||
<div class="input-group input-group-sm w-auto">
|
||||
<input type="text" name="search_terverifikasi" class="form-control" placeholder="Cari nama petani..." value="{{ request('search_terverifikasi') }}">
|
||||
<button type="submit" class="btn btn-outline-primary"><i class="icon-base ti tabler-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-hover">
|
||||
<thead class="border-top">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Nama Petani</th>
|
||||
<th>Komoditas</th>
|
||||
<th>Desa</th>
|
||||
<th>Enumerator</th>
|
||||
<th>Diverifikasi Oleh</th>
|
||||
<th>Terakhir Diperbarui</th>
|
||||
<th class="text-center">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($petaniTerverifikasi as $index => $item)
|
||||
<tr class="btn-buka-rincian"
|
||||
data-url="{{ route('monitoring-verifikasi.petani.verifikasi.show', $item->id) }}"
|
||||
data-judul="{{ $item->nama }}" title="Klik untuk melihat rincian verifikasi">
|
||||
<td>{{ $petaniTerverifikasi->firstItem() + $index }}</td>
|
||||
<td><span class="text-heading fw-medium">{{ $item->nama }}</span></td>
|
||||
<td>{{ $item->komoditas?->nama ?? '-' }}</td>
|
||||
<td>{{ $item->desaKelurahan?->nama ?? '-' }}</td>
|
||||
<td><span class="text-body-secondary">{{ $item->creator?->name ?? '-' }}</span></td>
|
||||
{{-- Data terverifikasi dikunci, jadi updated_by = yang memverifikasi --}}
|
||||
<td>
|
||||
<span class="d-block text-heading">{{ $item->updater?->name ?? '-' }}</span>
|
||||
@if ($item->updater?->role)
|
||||
<small class="text-body-secondary">{{ $item->updater->role->label() }}</small>
|
||||
@endif
|
||||
</td>
|
||||
<td><span class="text-body-secondary">{{ $item->updated_at?->translatedFormat('d M Y H:i') ?? '-' }}</span></td>
|
||||
<td class="text-center"><span class="badge bg-label-{{ $item->status->warna() }}">{{ $item->status->label() }}</span></td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="8" class="text-center py-4">Belum ada data petani yang terverifikasi.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-center justify-content-md-end border-top pt-4">
|
||||
{{ $petaniTerverifikasi->links('pagination::bootstrap-5') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kolom-detail" aria-hidden="true"></div>
|
||||
</div>
|
||||
@endif
|
||||
@@ -0,0 +1,118 @@
|
||||
@extends('monitoring-verifikasi.index')
|
||||
|
||||
@php
|
||||
$idSubTab = 'verifikasi';
|
||||
$subTabs = [
|
||||
'lengkap' => ['label' => 'Data Lengkap', 'ikon' => 'tabler-checklist', 'view' => 'monitoring-verifikasi.petani-lengkap', 'jumlah' => $petaniLengkap->total()],
|
||||
'terverifikasi' => ['label' => 'Terverifikasi', 'ikon' => 'tabler-rosette-discount-check', 'view' => 'monitoring-verifikasi.petani-terverifikasi', 'jumlah' => $petaniTerverifikasi->total()],
|
||||
];
|
||||
@endphp
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
(function () {
|
||||
const gayaTombolSwal = () => ({
|
||||
buttonsStyling: false,
|
||||
customClass: { confirmButton: 'btn btn-primary me-2', cancelButton: 'btn btn-label-secondary' },
|
||||
});
|
||||
|
||||
// Langkah verifikasi: 1 Input Skor → 2 Input Wajib → 3 Input Lainnya.
|
||||
function tampilkanLangkah(stepper, aktif) {
|
||||
stepper.querySelectorAll('.langkah-pane').forEach((pane) => {
|
||||
pane.classList.toggle('d-none', Number(pane.dataset.langkah) !== aktif);
|
||||
});
|
||||
|
||||
stepper.querySelectorAll('.langkah-item').forEach((item) => {
|
||||
const n = Number(item.dataset.langkah);
|
||||
const nomor = item.querySelector('.langkah-nomor');
|
||||
const selesai = n < aktif;
|
||||
|
||||
nomor.className = 'avatar-initial rounded-circle langkah-nomor '
|
||||
+ (n === aktif ? 'bg-primary text-white' : selesai ? 'bg-label-success' : 'bg-label-secondary');
|
||||
nomor.innerHTML = selesai ? '<i class="icon-base ti tabler-check icon-sm"></i>' : n;
|
||||
|
||||
// Langkah yang sudah dilewati bisa diklik untuk kembali.
|
||||
if (selesai) item.dataset.keLangkah = n; else delete item.dataset.keLangkah;
|
||||
item.classList.toggle('cursor-pointer', selesai);
|
||||
});
|
||||
|
||||
stepper.closest('.kartu-rincian-isi')?.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
document.addEventListener('click', function (e) {
|
||||
const tombol = e.target.closest('[data-ke-langkah]');
|
||||
if (!tombol) return;
|
||||
const stepper = tombol.closest('.stepper-verifikasi');
|
||||
if (stepper) tampilkanLangkah(stepper, Number(tombol.dataset.keLangkah));
|
||||
});
|
||||
|
||||
// Konfirmasi sebelum menandai Terverifikasi.
|
||||
document.addEventListener('submit', function (e) {
|
||||
const form = e.target.closest('.form-verifikasi-petani');
|
||||
if (!form || form.dataset.terkonfirmasi) return;
|
||||
|
||||
e.preventDefault();
|
||||
const kirim = () => { form.dataset.terkonfirmasi = '1'; form.submit(); };
|
||||
const pesan = `Data petani ${form.dataset.nama} sudah diperiksa dan akan ditandai Terverifikasi.`;
|
||||
|
||||
if (!window.Swal) {
|
||||
if (confirm(pesan)) kirim();
|
||||
return;
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
icon: 'question',
|
||||
title: 'Verifikasi Data Petani',
|
||||
text: pesan,
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Ya, Verifikasi',
|
||||
cancelButtonText: 'Batal',
|
||||
...gayaTombolSwal(),
|
||||
}).then((r) => { if (r.isConfirmed) kirim(); });
|
||||
});
|
||||
|
||||
// Kembalikan ke Draf (Belum Lengkap / ada temuan setelah diverifikasi): wajib isi catatan untuk enumerator.
|
||||
const escapeHtml = (teks) => String(teks).replace(/[&<>"']/g, (c) => '&#' + c.charCodeAt(0) + ';');
|
||||
|
||||
document.addEventListener('submit', function (e) {
|
||||
const form = e.target.closest('.form-kembalikan-draf');
|
||||
if (!form || form.dataset.terkonfirmasi) return;
|
||||
|
||||
e.preventDefault();
|
||||
const kirim = (catatan) => {
|
||||
form.querySelector('input[name="catatan"]').value = catatan.trim();
|
||||
form.dataset.terkonfirmasi = '1';
|
||||
form.submit();
|
||||
};
|
||||
|
||||
if (!window.Swal) {
|
||||
const catatan = prompt('Catatan untuk enumerator (wajib):');
|
||||
if (catatan && catatan.trim()) kirim(catatan);
|
||||
return;
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: form.dataset.judul || 'Kembalikan ke Draf',
|
||||
html: `Data petani <strong>${escapeHtml(form.dataset.nama)}</strong> akan dikembalikan ke <strong>Draf</strong>.<br>${escapeHtml(form.dataset.pesan || '')}`,
|
||||
input: 'textarea',
|
||||
inputPlaceholder: 'Contoh: Foto KTP belum diunggah, luas lahan perlu dicek ulang...',
|
||||
inputAttributes: { maxlength: 2000, rows: 4 },
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Kirim',
|
||||
cancelButtonText: 'Batal',
|
||||
inputValidator: (nilai) => !nilai?.trim() && 'Catatan wajib diisi.',
|
||||
...gayaTombolSwal(),
|
||||
}).then((r) => { if (r.isConfirmed) kirim(r.value); });
|
||||
});
|
||||
|
||||
@if (session('verifikasi_success') || session('verifikasi_error') || $errors->has('catatan'))
|
||||
window.addEventListener('load', function () {
|
||||
const pesan = @json(session('verifikasi_success') ?? session('verifikasi_error') ?? $errors->first('catatan'));
|
||||
const ikon = @json(session('verifikasi_success') ? 'success' : 'error');
|
||||
window.Swal ? Swal.fire({ icon: ikon, text: pesan, ...gayaTombolSwal() }) : alert(pesan);
|
||||
});
|
||||
@endif
|
||||
})();
|
||||
</script>
|
||||
@endpush
|
||||
@@ -320,8 +320,23 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@if ($petani && $petani->catatan && $petani->status === \App\Enums\StatusDataPetani::DRAFT)
|
||||
{{-- Dikembalikan koordinator (Belum Lengkap): yang perlu diperbaiki enumerator --}}
|
||||
<div class="card border border-warning mb-6">
|
||||
<div class="card-body py-4 d-flex align-items-start">
|
||||
<span class="avatar avatar-sm flex-shrink-0 me-3">
|
||||
<span class="avatar-initial rounded bg-label-warning"><i class="icon-base ti tabler-message-exclamation icon-20px"></i></span>
|
||||
</span>
|
||||
<div>
|
||||
<h6 class="mb-1">Catatan Koordinator</h6>
|
||||
<p class="mb-0" style="white-space: pre-line;">{{ $petani->catatan }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="nav-align-top">
|
||||
@if(!$petani)
|
||||
<ul class="nav nav-pills flex-column flex-md-row mb-6 row-gap-2 nav-pills-custom-spacing">
|
||||
@@ -404,4 +419,8 @@
|
||||
|
||||
@if ($petani)
|
||||
<x-kelengkapan-petani :petani="$petani" :lahan="$lahanSelected ?? null" />
|
||||
|
||||
@if ($petani->status === \App\Enums\StatusDataPetani::TERVERIFIKASI)
|
||||
<x-kunci-petani-terverifikasi />
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@@ -359,7 +359,12 @@
|
||||
<div class="d-flex align-items-center">
|
||||
<!-- <a href="{{ route('petani.show', $item->id) }}" class="btn btn-icon btn-text-secondary rounded-pill view-record"><i class="ti tabler-eye ti-md"></i></a> -->
|
||||
<a href="{{ route('petani.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>
|
||||
@if ($item->status === \App\Enums\StatusDataPetani::TERVERIFIKASI)
|
||||
{{-- Terverifikasi: tidak bisa dihapus --}}
|
||||
<span class="btn btn-icon btn-text-secondary rounded-pill disabled" title="Data terverifikasi tidak dapat dihapus"><i class="ti tabler-lock ti-md"></i></span>
|
||||
@else
|
||||
<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>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user