feat(noc): implementasi mutual exclusive selection untuk status kurang dan lebih bayar

- Menambahkan JavaScript untuk mutual exclusive selection antara status kurang bayar dan lebih bayar
- Hanya satu status yang bisa dipilih pada satu waktu untuk mencegah konflik data
- Implementasi fungsi resetFields() untuk membersihkan field yang tidak dipilih
- Menambahkan event handler untuk toggle visibility field berdasarkan pilihan status
- Menambahkan logging untuk tracking perubahan status pembayaran
- Field nominal dan bukti pengembalian otomatis direset ketika status berubah
- Mempertahankan UI existing dengan checkbox namun menambahkan logika mutual exclusive
- Menambahkan validasi client-side untuk mencegah input data yang tidak konsisten
- Support untuk readonly mode ketika memo penyelesaian sudah ada
- Implementasi function-level comments untuk dokumentasi kode
This commit is contained in:
Daeng Deni Mardaeni
2025-07-31 13:24:18 +07:00
parent bc7fef05f6
commit 19fb39b02f
5 changed files with 262 additions and 1 deletions

View File

@@ -139,6 +139,112 @@
</div>
<!-- Field Status Kurang Bayar -->
<div class="flex flex-wrap gap-2.5 items-baseline lg:flex-nowrap">
<label class="form-label max-w-56">
Status Kurang Bayar
</label>
<div class="flex flex-wrap items-baseline w-full">
<div class="flex gap-4 items-center">
<label class="checkbox-group">
<input class="checkbox checkbox-sm" name="status_kurang_bayar" id="status_kurang_bayar"
value="1" type="checkbox"
{{ old('status_kurang_bayar', $persetujuanPenawaran->noc->status_kurang_bayar ?? false) ? 'checked' : '' }}
{{ $hasMemo ? 'disabled' : '' }}>
<span class="checkbox-label">
Ya, ada kurang bayar
</span>
</label>
</div>
@error('status_kurang_bayar')
<em class="text-sm alert text-danger">{{ $message }}</em>
@enderror
</div>
</div>
<!-- Field Nominal Kurang Bayar -->
<div class="flex flex-wrap gap-2.5 items-baseline lg:flex-nowrap" id="nominal_kurang_bayar_section"
style="display: none;">
<label class="form-label max-w-56">
Nominal Kurang Bayar
</label>
<div class="flex flex-wrap items-baseline w-full">
<input type="number" name="nominal_kurang_bayar" id="nominal_kurang_bayar"
class="input w-full @error('nominal_kurang_bayar') border-danger bg-danger-light @enderror"
value="{{ old('nominal_kurang_bayar', $persetujuanPenawaran->noc->nominal_kurang_bayar ?? '') }}"
placeholder="Masukkan nominal kurang bayar" {{ $hasMemo ? 'readonly' : '' }}>
@error('nominal_kurang_bayar')
<em class="text-sm alert text-danger">{{ $message }}</em>
@enderror
</div>
</div>
<!-- Field Status Lebih Bayar -->
<div class="flex flex-wrap gap-2.5 items-baseline lg:flex-nowrap">
<label class="form-label max-w-56">
Status Lebih Bayar
</label>
<div class="flex flex-wrap items-baseline w-full">
<div class="flex gap-4 items-center">
<label class="checkbox-group">
<input class="checkbox checkbox-sm" name="status_lebih_bayar" id="status_lebih_bayar"
value="1" type="checkbox"
{{ old('status_lebih_bayar', $persetujuanPenawaran->noc->status_lebih_bayar ?? false) ? 'checked' : '' }}
{{ $hasMemo ? 'disabled' : '' }}>
<span class="checkbox-label">Ya, ada lebih bayar </span>
</label>
</div>
@error('status_lebih_bayar')
<em class="text-sm alert text-danger">{{ $message }}</em>
@enderror
</div>
</div>
<!-- Field Nominal Lebih Bayar -->
<div class="flex flex-wrap gap-2.5 items-baseline lg:flex-nowrap" id="nominal_lebih_bayar_section"
style="display: none;">
<label class="form-label max-w-56">
Nominal Lebih Bayar
</label>
<div class="flex flex-wrap items-baseline w-full">
<input type="number" name="nominal_lebih_bayar" id="nominal_lebih_bayar"
class="input w-full @error('nominal_lebih_bayar') border-danger bg-danger-light @enderror"
value="{{ old('nominal_lebih_bayar', $persetujuanPenawaran->noc->nominal_lebih_bayar ?? '') }}"
placeholder="Masukkan nominal lebih bayar" {{ $hasMemo ? 'readonly' : '' }}>
@error('nominal_lebih_bayar')
<em class="text-sm alert text-danger">{{ $message }}</em>
@enderror
</div>
</div>
<!-- Field Bukti Pengembalian -->
<div class="flex flex-wrap gap-2.5 items-baseline lg:flex-nowrap" id="bukti_pengembalian_section"
style="display: none;">
<label class="form-label max-w-56">
Bukti Pengembalian
</label>
<div class="flex flex-wrap items-baseline w-full">
@if (!$hasMemo)
<input type="file" name="bukti_pengembalian" id="bukti_pengembalian"
class="file-input w-full @error('bukti_pengembalian') border-danger bg-danger-light @enderror"
accept=".pdf,.jpg,.jpeg,.png">
@error('bukti_pengembalian')
<em class="text-sm alert text-danger">{{ $message }}</em>
@enderror
@endif
@if (isset($persetujuanPenawaran->noc->bukti_pengembalian) && !empty($persetujuanPenawaran->noc->bukti_pengembalian))
<div class="flex items-center mt-2">
<a href="{{ Storage::url($persetujuanPenawaran->noc->bukti_pengembalian) }}"
target="_blank" class="badge badge-sm badge-outline badge-warning">
<i class="mr-2 ki-filled ki-eye"></i> Lihat File
</a>
</div>
@endif
</div>
</div>
<div class="flex flex-wrap gap-2.5 items-baseline lg:flex-nowrap">
<label class="form-label max-w-56">
Bukti KSL
@@ -274,3 +380,91 @@
</div>
</div>
@endsection
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
/**
* Fungsi untuk mengelola mutual exclusive selection antara kurang bayar dan lebih bayar
* Hanya satu status yang bisa dipilih pada satu waktu
*/
const statusKurangBayar = document.getElementById('status_kurang_bayar');
const statusLebihBayar = document.getElementById('status_lebih_bayar');
const nominalKurangBayarSection = document.getElementById('nominal_kurang_bayar_section');
const nominalLebihBayarSection = document.getElementById('nominal_lebih_bayar_section');
const buktiPengembalianSection = document.getElementById('bukti_pengembalian_section');
/**
* Fungsi untuk reset field dan section visibility
* @param {string} type - 'kurang' atau 'lebih'
*/
function resetFields(type) {
if (type === 'kurang') {
// Reset field lebih bayar
statusLebihBayar.checked = false;
nominalLebihBayarSection.style.display = 'none';
buktiPengembalianSection.style.display = 'none';
document.getElementById('nominal_lebih_bayar').value = '';
document.getElementById('bukti_pengembalian').value = '';
} else if (type === 'lebih') {
// Reset field kurang bayar
statusKurangBayar.checked = false;
nominalKurangBayarSection.style.display = 'none';
document.getElementById('nominal_kurang_bayar').value = '';
}
}
/**
* Event handler untuk status kurang bayar
* Menampilkan field nominal kurang bayar dan menyembunyikan field lebih bayar
*/
if (statusKurangBayar) {
// Set initial state
if (statusKurangBayar.checked) {
nominalKurangBayarSection.style.display = 'flex';
resetFields('kurang');
}
statusKurangBayar.addEventListener('change', function() {
if (this.checked) {
nominalKurangBayarSection.style.display = 'flex';
resetFields('kurang');
console.log('Status kurang bayar dipilih, field lebih bayar direset');
} else {
nominalKurangBayarSection.style.display = 'none';
document.getElementById('nominal_kurang_bayar').value = '';
console.log('Status kurang bayar dibatalkan');
}
});
}
/**
* Event handler untuk status lebih bayar
* Menampilkan field nominal dan bukti pengembalian, menyembunyikan field kurang bayar
*/
if (statusLebihBayar) {
// Set initial state
if (statusLebihBayar.checked) {
nominalLebihBayarSection.style.display = 'flex';
buktiPengembalianSection.style.display = 'flex';
resetFields('lebih');
}
statusLebihBayar.addEventListener('change', function() {
if (this.checked) {
nominalLebihBayarSection.style.display = 'flex';
buktiPengembalianSection.style.display = 'flex';
resetFields('lebih');
console.log('Status lebih bayar dipilih, field kurang bayar direset');
} else {
nominalLebihBayarSection.style.display = 'none';
buktiPengembalianSection.style.display = 'none';
document.getElementById('nominal_lebih_bayar').value = '';
document.getElementById('bukti_pengembalian').value = '';
console.log('Status lebih bayar dibatalkan');
}
});
}
});
</script>
@endpush