Initial Commit
This commit is contained in:
616
resources/views/surveyor/components/inspeksi.blade.php
Normal file
616
resources/views/surveyor/components/inspeksi.blade.php
Normal file
@@ -0,0 +1,616 @@
|
||||
@extends('layouts.main')
|
||||
|
||||
@section('breadcrumbs')
|
||||
{{ Breadcrumbs::render(request()->route()->getName()) }}
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
@include('lpj::assetsku.includenya')
|
||||
<div class="w-full grid gap-5 lg:gap-7.5 mx-auto">
|
||||
<form id="formInspeksi" method="POST" enctype="multipart/form-data" class="grid gap-5">
|
||||
@csrf
|
||||
<input id="permohonan_id" type="hidden" name="permohonan_id" value="{{ $permohonan->id }}">
|
||||
<input id="dokument_id" type="hidden" name="dokument_id" value="{{ request('dokument') }}">
|
||||
<input type="hidden" name="nomor_registrasi" value="{{ $permohonan->nomor_registrasi }}">
|
||||
|
||||
@if (strtolower($permohonan->tujuanPenilaian->name) == 'rap')
|
||||
<input type="hidden" name="action" value="rap">
|
||||
<input type="hidden" name="type" value="rap">
|
||||
|
||||
@include('lpj::surveyor.components.header')
|
||||
@include('lpj::surveyor.components.rap')
|
||||
@else
|
||||
@foreach ($permohonan->debiture->documents as $dokumen)
|
||||
@if ($dokumen->jenisJaminan)
|
||||
@php
|
||||
$formKategori = json_decode($dokumen->jenisJaminan->form_kategori, true);
|
||||
@endphp
|
||||
@if (isset($formKategori) && $formKategori)
|
||||
@php
|
||||
$kategoriArray = is_array($formKategori) ? $formKategori : [$formKategori];
|
||||
$kategoriUnik = array_unique($kategoriArray);
|
||||
@endphp
|
||||
<input type="hidden" name="action" value="{{ implode(',', $kategoriUnik) }}">
|
||||
<input type="hidden" name="type" value="{{ implode(',', $kategoriUnik) }}">
|
||||
@if (array_intersect($kategoriUnik, ['tanah', 'bangunan', 'apartemen-kantor']))
|
||||
@include('lpj::surveyor.components.header')
|
||||
@endif
|
||||
|
||||
@foreach ($kategoriUnik as $kategori)
|
||||
{{-- Tampilkan komponen sesuai kategori --}}
|
||||
@include('lpj::surveyor.components.' . str_replace('-', '-', $kategori), [
|
||||
'dokumen' => $dokumen,
|
||||
])
|
||||
@endforeach
|
||||
@endif
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
<div class="card border border-agi-100 w-full rounded-lg shadow-md overflow-hidden">
|
||||
<div class="card-header light:bg-agi-50">
|
||||
<h3 class="card-title uppercase">
|
||||
Tanda Tangan
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-baseline justify-between flex-wrap lg:flex-nowrap">
|
||||
@foreach (['penilai', 'cabang', 'debitur', 'kjpp'] as $type)
|
||||
@include('lpj::component.signature-pad', ['type' => $type])
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<span class="text-sm text-danger">* Harap Menyimpan tanda tangan terlebih dahulu</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-2" style="margin-right: 20px; margin-top: 20px">
|
||||
<button type="button" class="btn btn-primary" id="saveButton" onclick="submitData()">
|
||||
<i class="ki-filled ki-save-2"></i>
|
||||
<span id="saveButtonText">Simpan</span>
|
||||
</button>
|
||||
<a href="{{ route('surveyor.print_out_inspeksi', ['permohonan_id' => $permohonan->id, 'dokument_id' => request('dokument'), 'jenis_jaminan_id' => request('jenis_jaminan')]) }}"
|
||||
class="btn btn-info" id="saveButton">
|
||||
<i class="ki-filled ki-printer"></i>
|
||||
<span>Cetak Form Inspeksi</span>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@php
|
||||
use Modules\Usermanagement\Models\User;
|
||||
$cabangUser = User::where('id', $permohonan->user->id)->first();
|
||||
|
||||
// print_r($cabangUser->sign);
|
||||
|
||||
@endphp
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script src="{{ asset('vendor/signature.pad.js') }}"></script>
|
||||
<script type="text/javascript">
|
||||
const datas = @json($forminspeksi);
|
||||
console.log(datas);
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const signaturePads = {};
|
||||
const types = ['penilai', 'cabang', 'debitur', 'kjpp'];
|
||||
|
||||
// Initialize all signature pads
|
||||
types.forEach(type => initSignaturePad(type));
|
||||
|
||||
function initSignaturePad(type) {
|
||||
const canvas = document.getElementById(`signature-pad-${type}`);
|
||||
if (!canvas) return;
|
||||
|
||||
// Improved canvas sizing with strict boundary control
|
||||
function resizeCanvas() {
|
||||
const container = canvas.closest('.signature-pad-container');
|
||||
const containerWidth = container.clientWidth;
|
||||
|
||||
// Set canvas style dimensions
|
||||
canvas.style.width = '100%';
|
||||
canvas.style.height = `${containerWidth * 0.5}px`; // 2:1 aspect ratio
|
||||
|
||||
// Set actual canvas dimensions with high DPI support
|
||||
const ratio = window.devicePixelRatio || 1;
|
||||
canvas.width = containerWidth * ratio;
|
||||
canvas.height = (containerWidth * 0.5) * ratio;
|
||||
|
||||
// Scale canvas context
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.scale(ratio, ratio);
|
||||
|
||||
// Clear and redraw existing signature if any
|
||||
if (signaturePads[type] && !signaturePads[type].isEmpty()) {
|
||||
const signaturePad = signaturePads[type];
|
||||
const imageData = signaturePad.toData();
|
||||
signaturePad.clear();
|
||||
signaturePad.fromData(imageData);
|
||||
}
|
||||
}
|
||||
|
||||
// Create signature pad with boundary and scaling control
|
||||
const signaturePad = new SignaturePad(canvas, {
|
||||
backgroundColor: 'rgba(255, 255, 255, 0)',
|
||||
penColor: 'rgb(0, 0, 0)',
|
||||
minWidth: 0.5,
|
||||
maxWidth: 2.5,
|
||||
throttle: 16,
|
||||
dotSize: 2,
|
||||
|
||||
// Custom function to control signature drawing
|
||||
onBegin: (event) => {
|
||||
const ctx = canvas.getContext('2d');
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const scaleX = canvas.width / rect.width;
|
||||
const scaleY = canvas.height / rect.height;
|
||||
|
||||
// Ensure drawing stays within canvas
|
||||
if (
|
||||
event.clientX < rect.left ||
|
||||
event.clientX > rect.right ||
|
||||
event.clientY < rect.top ||
|
||||
event.clientY > rect.bottom
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
signaturePads[type] = signaturePad;
|
||||
|
||||
// Initial resize
|
||||
resizeCanvas();
|
||||
|
||||
// Load existing signature
|
||||
if (type === 'penilai' || type === 'cabang') {
|
||||
loadPenilaiAndCabangSignature(type, signaturePad);
|
||||
} else {
|
||||
loadSignature(type, signaturePad);
|
||||
}
|
||||
|
||||
// Add event listeners
|
||||
addEventListeners(type, signaturePad);
|
||||
|
||||
// Add resize listener
|
||||
window.addEventListener('resize', () => {
|
||||
resizeCanvas();
|
||||
});
|
||||
}
|
||||
|
||||
function drawSignature(signaturePad, imageUrl) {
|
||||
const image = new Image();
|
||||
image.crossOrigin = 'Anonymous';
|
||||
image.onload = function() {
|
||||
const ctx = signaturePad.canvas.getContext('2d');
|
||||
const canvasWidth = signaturePad.canvas.width;
|
||||
const canvasHeight = signaturePad.canvas.height;
|
||||
|
||||
// Clear previous content
|
||||
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||
|
||||
// Calculate scaling to fit within canvas while maintaining aspect ratio
|
||||
const scale = Math.min(
|
||||
canvasWidth / image.width,
|
||||
canvasHeight / image.height
|
||||
);
|
||||
|
||||
const scaledWidth = image.width * scale;
|
||||
const scaledHeight = image.height * scale;
|
||||
|
||||
// Center the image
|
||||
const x = (canvasWidth - scaledWidth) / 2;
|
||||
const y = (canvasHeight - scaledHeight) / 2;
|
||||
|
||||
// Draw the scaled and centered image
|
||||
ctx.drawImage(image, x, y, scaledWidth, scaledHeight);
|
||||
};
|
||||
image.onerror = function() {
|
||||
console.error('Error loading signature image');
|
||||
};
|
||||
image.src = imageUrl;
|
||||
}
|
||||
|
||||
function addEventListeners(type, signaturePad) {
|
||||
document.getElementById(`save-${type}`)?.addEventListener('click', () => saveSignature(type,
|
||||
signaturePad));
|
||||
document.getElementById(`clear-${type}`)?.addEventListener('click', () => clearSignature(
|
||||
signaturePad));
|
||||
document.getElementById(`delete-${type}`)?.addEventListener('click', () => deleteSignature(type,
|
||||
signaturePad));
|
||||
}
|
||||
|
||||
function saveSignature(type, signaturePad) {
|
||||
// Prevent saving empty signature for debitur and kjjp
|
||||
if (signaturePad.isEmpty() && type !== 'penilai' && type !== 'cabang') {
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Peringatan',
|
||||
text: 'Harap memberikan tanda tangan terlebih dahulu.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Use high-quality PNG with appropriate scaling
|
||||
const signatureDataUrl = signaturePad.isEmpty() ?
|
||||
(type === 'penilai' ?
|
||||
`{{ asset('storage/signatures/' . Auth::user()->id . '/' . Auth::user()->sign) }}` :
|
||||
(type === 'cabang' ?
|
||||
`{{ asset('storage/signatures/' . $cabangUser->id . '/' . $cabangUser->sign) }}` :
|
||||
'')) :
|
||||
signaturePad.toDataURL('image/png', 1.0); // Use full quality
|
||||
|
||||
const data = {
|
||||
signature: signatureDataUrl,
|
||||
type: type,
|
||||
name: document.getElementById(`name-${type}`)?.value,
|
||||
document_id: document.getElementById('dokument_id')?.value,
|
||||
permohonan_id: document.getElementById('permohonan_id')?.value
|
||||
};
|
||||
|
||||
Swal.fire({
|
||||
title: 'Menyimpan...',
|
||||
allowOutsideClick: false,
|
||||
didOpen: () => Swal.showLoading()
|
||||
});
|
||||
|
||||
fetch(`{{ url('/surveyor/signatures') }}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
Swal.close();
|
||||
if (data.success) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: 'Tanda tangan berhasil disimpan!',
|
||||
timer: 1500
|
||||
});
|
||||
} else {
|
||||
throw new Error(data.message || 'Terjadi kesalahan');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: error.message || 'Terjadi kesalahan saat menyimpan tanda tangan'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function drawSignature(signaturePad, imageUrl) {
|
||||
const image = new Image();
|
||||
image.crossOrigin = 'Anonymous'; // Handle cross-origin images
|
||||
image.onload = function() {
|
||||
const ctx = signaturePad.canvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, signaturePad.canvas.width, signaturePad.canvas.height);
|
||||
|
||||
// Calculate scaling to fit within canvas while maintaining aspect ratio
|
||||
const scale = Math.min(
|
||||
signaturePad.canvas.width / image.width,
|
||||
signaturePad.canvas.height / image.height
|
||||
);
|
||||
|
||||
const scaledWidth = image.width * scale;
|
||||
const scaledHeight = image.height * scale;
|
||||
|
||||
const x = (signaturePad.canvas.width - scaledWidth) / 2;
|
||||
const y = (signaturePad.canvas.height - scaledHeight) / 2;
|
||||
|
||||
ctx.drawImage(image, x, y, scaledWidth, scaledHeight);
|
||||
};
|
||||
image.onerror = function() {
|
||||
console.error('Error loading signature image');
|
||||
};
|
||||
image.src = imageUrl;
|
||||
}
|
||||
|
||||
function loadPenilaiAndCabangSignature(type, signaturePad) {
|
||||
const nameInputElement = document.getElementById(`name-${type}`);
|
||||
|
||||
const params = new URLSearchParams({
|
||||
document_id: document.getElementById('dokument_id')?.value,
|
||||
permohonan_id: document.getElementById('permohonan_id')?.value
|
||||
});
|
||||
|
||||
fetch(`{{ url('/surveyor/signatures/${type}') }}?${params}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success && data.data?.signature) {
|
||||
drawSignature(signaturePad, data.data.signature);
|
||||
if (nameInputElement) {
|
||||
nameInputElement.value = data.data.name || '';
|
||||
}
|
||||
} else {
|
||||
const signUrl = type === 'penilai' ?
|
||||
`{{ asset('storage/signatures/' . Auth::user()->id . '/' . Auth::user()->sign) }}` :
|
||||
`{{ asset('storage/signatures/' . $cabangUser->id . '/' . $cabangUser->sign) }}`;
|
||||
|
||||
drawSignature(signaturePad, signUrl);
|
||||
|
||||
const defaultName = type === 'penilai' ?
|
||||
`{{ Auth::user()->name }}` :
|
||||
`{{ $cabangUser->name }}`;
|
||||
if (nameInputElement) {
|
||||
nameInputElement.value = defaultName;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => console.error(`Error loading ${type} signature:`, error));
|
||||
}
|
||||
|
||||
|
||||
function saveSignature(type, signaturePad) {
|
||||
if (signaturePad.isEmpty() && type !== 'penilai' && type !== 'cabang') {
|
||||
Swal.fire({
|
||||
icon: 'warning',
|
||||
title: 'Peringatan',
|
||||
text: 'Harap memberikan tanda tangan terlebih dahulu.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const signatureDataUrl = signaturePad.isEmpty() ?
|
||||
(type === 'penilai' ?
|
||||
`{{ asset('storage/signatures/' . Auth::user()->id . '/' . Auth::user()->sign) }}` :
|
||||
(type === 'cabang' ?
|
||||
`{{ asset('storage/signatures/' . $cabangUser->id . '/' . $cabangUser->sign) }}` :
|
||||
'')) :
|
||||
signaturePad.toDataURL('image/png');
|
||||
|
||||
const data = {
|
||||
signature: signatureDataUrl,
|
||||
type: type,
|
||||
name: document.getElementById(`name-${type}`)?.value,
|
||||
document_id: document.getElementById('dokument_id')?.value,
|
||||
permohonan_id: document.getElementById('permohonan_id')?.value
|
||||
};
|
||||
|
||||
Swal.fire({
|
||||
title: 'Menyimpan...',
|
||||
allowOutsideClick: false,
|
||||
didOpen: () => Swal.showLoading()
|
||||
});
|
||||
|
||||
fetch(`{{ url('/surveyor/signatures') }}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
Swal.close();
|
||||
if (data.success) {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: 'Tanda tangan berhasil disimpan!',
|
||||
timer: 1500
|
||||
});
|
||||
} else {
|
||||
throw new Error(data.message || 'Terjadi kesalahan');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: error.message || 'Terjadi kesalahan saat menyimpan tanda tangan'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function loadSignature(type, signaturePad) {
|
||||
const nameInputElement = document.getElementById(`name-${type}`);
|
||||
const params = new URLSearchParams({
|
||||
document_id: document.getElementById('dokument_id')?.value,
|
||||
permohonan_id: document.getElementById('permohonan_id')?.value
|
||||
});
|
||||
|
||||
fetch(`{{ url('/surveyor/signatures/${type}') }}?${params}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success && data.data?.signature) {
|
||||
drawSignature(signaturePad, data.data.signature);
|
||||
}
|
||||
if (nameInputElement) {
|
||||
nameInputElement.value = data.data?.name || '';
|
||||
}
|
||||
|
||||
})
|
||||
.catch(error => console.error('Error loading signature:', error));
|
||||
}
|
||||
|
||||
function drawSignature(signaturePad, imageUrl) {
|
||||
const image = new Image();
|
||||
image.onload = function() {
|
||||
const ctx = signaturePad.canvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, signaturePad.canvas.width, signaturePad.canvas.height);
|
||||
ctx.drawImage(image, 0, 0, signaturePad.canvas.width, signaturePad.canvas.height);
|
||||
};
|
||||
image.src = imageUrl;
|
||||
}
|
||||
|
||||
function deleteSignature(type, signaturePad) {
|
||||
Swal.fire({
|
||||
title: 'Konfirmasi',
|
||||
text: 'Apakah Anda yakin ingin menghapus tanda tangan ini?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Ya, Hapus',
|
||||
cancelButtonText: 'Batal'
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
const data = {
|
||||
type: type,
|
||||
document_id: document.getElementById('dokument_id')?.value,
|
||||
permohonan_id: document.getElementById('permohonan_id')?.value
|
||||
};
|
||||
|
||||
fetch(`{{ url('/surveyor/signatures/${type}') }}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}',
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
clearSignature(signaturePad);
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Berhasil',
|
||||
text: 'Tanda tangan berhasil dihapus!',
|
||||
timer: 1500
|
||||
});
|
||||
} else {
|
||||
throw new Error(data.message || 'Terjadi kesalahan');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error',
|
||||
text: error.message ||
|
||||
'Terjadi kesalahan saat menghapus tanda tangan'
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clearSignature(signaturePad) {
|
||||
signaturePad.clear();
|
||||
}
|
||||
|
||||
// Handle window resize untuk canvas responsif
|
||||
window.addEventListener('resize', function() {
|
||||
types.forEach(type => {
|
||||
const canvas = document.getElementById(`signature-pad-${type}`);
|
||||
if (canvas) {
|
||||
setCanvasSize(canvas);
|
||||
const signaturePad = signaturePads[type];
|
||||
if (type === 'penilai' || type === 'cabang') {
|
||||
loadPenilaiAndCabangSignature(type, signaturePad);
|
||||
} else {
|
||||
loadSignature(type, signaturePad);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function submitData() {
|
||||
showLoadingSwal('Mengirim data ke server...');
|
||||
const form = document.querySelector('form');
|
||||
const formData = new FormData(form);
|
||||
|
||||
const fotoFields = [
|
||||
'foto_gistaru',
|
||||
'foto_bhumi',
|
||||
'foto_argis_region',
|
||||
'foto_tempat',
|
||||
'foto_sentuh_tanahku',
|
||||
'upload_gs'
|
||||
];
|
||||
|
||||
fotoFields.forEach((field) => {
|
||||
formData.delete(field);
|
||||
});
|
||||
$.ajax({
|
||||
url: '{{ route('surveyor.store') }}',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': '{{ csrf_token() }}'
|
||||
},
|
||||
success: function(response) {
|
||||
hideLoadingSwal();
|
||||
if (response.success) {
|
||||
Swal.fire({
|
||||
title: 'Berhasil!',
|
||||
text: response.message,
|
||||
icon: 'success',
|
||||
confirmButtonText: 'OK'
|
||||
}).then((response) => {
|
||||
if (response.isConfirmed) {
|
||||
// window.location.href =
|
||||
// '{{ route('surveyor.show', ['id' => $permohonan->id]) }}';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: response.message || 'Terjadi kesalahan',
|
||||
icon: 'error',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
}
|
||||
console.log(response);
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
hideLoadingSwal();
|
||||
if (status === 'timeout') {
|
||||
Swal.fire({
|
||||
title: 'Timeout!',
|
||||
text: 'Waktu permintaan habis. Silakan coba lagi.',
|
||||
icon: 'warning',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
return;
|
||||
}
|
||||
let errors = xhr.responseJSON?.errors;
|
||||
$('.alert').text('');
|
||||
if (errors) {
|
||||
$.each(errors, function(key, value) {
|
||||
$(`#error-${key}`).text(value[0]);
|
||||
toastrErrorBuild(value[0]);
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: xhr.responseJSON?.message || 'Terjadi kesalahan saat mengirim data.',
|
||||
icon: 'error',
|
||||
confirmButtonText: 'OK'
|
||||
});
|
||||
}
|
||||
},
|
||||
timeout: 10000
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Ensure existing remove buttons are functional
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const removeButtons = document.querySelectorAll('.remove-btn');
|
||||
removeButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
this.closest('.perwakilan').remove();
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.number-format').forEach(input => {
|
||||
input.addEventListener('input', function() {
|
||||
formatNumber(this);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@include('lpj::surveyor.js.utils')
|
||||
@endpush
|
||||
Reference in New Issue
Block a user