NIM_E31222518/resources/views/keranjang/index.blade.php

1714 lines
76 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@extends('layouts.dashboard')
@section('content')
<meta name="csrf-token" content="{{ csrf_token() }}">
<style>
.item-li {
transition: all 0.3s ease;
}
</style>
<script>
// Setup CSRF token untuk semua request Ajax
document.addEventListener('DOMContentLoaded', function() {
// Get CSRF token dari meta tag
var token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
// Setup global headers untuk semua Fetch API request
window.originalFetch = window.fetch;
window.fetch = function(url, options) {
options = options || {};
options.headers = options.headers || {};
options.headers['X-CSRF-TOKEN'] = token;
return window.originalFetch(url, options);
};
console.log('CSRF token setup untuk semua request Ajax');
});
// Format angka sebagai Rupiah
function formatRupiah(angka) {
// Pastikan angka adalah tipe number
angka = typeof angka === 'string' ? parseInt(angka.replace(/[^\d]/g, '')) : angka;
// Jika bukan angka, return 0
if (isNaN(angka)) angka = 0;
return new Intl.NumberFormat('id-ID').format(angka);
}
// Update total dari item yang dipilih
function updateTotal() {
// Ambil semua checkbox yang dicentang
var checkboxes = document.querySelectorAll('.item-checkbox:checked');
var count = checkboxes.length;
var total = 0;
console.log('Update total untuk', count, 'item');
// Hitung total harga
for (var i = 0; i < checkboxes.length; i++) {
var checkbox = checkboxes[i];
// Ambil nilai jumlah dari input yang terkait
var listItem = checkbox.closest('li');
var jumlahInput = listItem.querySelector('input[name="jumlah"]');
var jumlah = jumlahInput ? parseInt(jumlahInput.value) : parseInt(checkbox.getAttribute('data-jumlah') || 1);
// Ambil harga satuan dari atribut data-harga-satuan
var hargaSatuan = parseInt(checkbox.getAttribute('data-harga-satuan') || 0);
// Hitung total harga item (harga satuan × jumlah)
var itemTotal = hargaSatuan * jumlah;
console.log('Item', i+1, 'Jumlah:', jumlah, 'Harga Satuan:', hargaSatuan, 'Total Item:', itemTotal);
total += itemTotal;
// Update data-price agar konsisten dengan jumlah saat ini
checkbox.setAttribute('data-price', itemTotal);
}
console.log('Total harga semua item:', total);
// Update tampilan subtotal
document.getElementById('selected-count').textContent = count;
document.getElementById('selected-total').textContent = formatRupiah(total);
document.getElementById('checkout-count').textContent = count;
// Update tombol checkout
var checkoutBtn = document.getElementById('checkout-button');
if (count > 0) {
checkoutBtn.disabled = false;
checkoutBtn.classList.remove('bg-gray-400', 'cursor-not-allowed');
checkoutBtn.classList.add('bg-[#2C7A7B]', 'hover:bg-[#1C6B6B]');
} else {
checkoutBtn.disabled = true;
checkoutBtn.classList.add('bg-gray-400', 'cursor-not-allowed');
checkoutBtn.classList.remove('bg-[#2C7A7B]', 'hover:bg-[#1C6B6B]');
}
// Update tombol hapus
var deleteBtn = document.getElementById('delete-selected');
if (count > 0) {
deleteBtn.style.display = 'block';
deleteBtn.classList.remove('hidden');
} else {
deleteBtn.style.display = 'none';
deleteBtn.classList.add('hidden');
}
// Update kondisi checkbox "Pilih Semua"
var selectAll = document.getElementById('select-all');
var allCheckboxes = document.querySelectorAll('.item-checkbox');
selectAll.checked = (allCheckboxes.length > 0 && count === allCheckboxes.length);
}
// Pilih atau batalkan pilih semua item
function pilihSemua() {
var isChecked = document.getElementById('select-all').checked;
var checkboxes = document.querySelectorAll('.item-checkbox');
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].checked = isChecked;
}
updateTotal();
}
// Tambah jumlah item
function tambahJumlah(btn, event) {
if (event) event.preventDefault();
var form = btn.closest('form');
var input = form.querySelector('input[name="jumlah"]');
var maxStok = parseInt(form.querySelector('input[name="max_stok"]').value);
var currentValue = parseInt(input.value);
// Nonaktifkan tombol jika sudah mencapai batas
var minusBtn = form.querySelector('button:first-of-type');
var plusBtn = form.querySelector('button:last-of-type');
if (currentValue < maxStok) {
// Tambahkan nilai langsung
input.value = currentValue + 1;
// Update status tombol sebelum submit
minusBtn.disabled = false;
minusBtn.classList.remove('opacity-50');
if (currentValue + 1 >= maxStok) {
plusBtn.disabled = true;
plusBtn.classList.add('opacity-50');
}
// Update data-jumlah pada checkbox sebelum submit
var listItem = form.closest('li');
var checkbox = listItem.querySelector('.item-checkbox');
if (checkbox) {
checkbox.setAttribute('data-jumlah', currentValue + 1);
// Jika checkbox tercentang, perbarui total sementara untuk UI responsif
if (checkbox.checked) {
var hargaSatuan = parseInt(checkbox.getAttribute('data-harga-satuan') || 0);
var newTotalPrice = hargaSatuan * (currentValue + 1);
checkbox.setAttribute('data-price', newTotalPrice);
// Update total tampilan segera sebelum submit
updateTotal();
}
}
try {
// Simpan dengan cara tradisional via iframe
submitFormViaIframe(form);
} catch (e) {
console.error('Error submitFormViaIframe:', e);
// Gunakan metode alternatif jika iframe gagal
updateJumlahDirect(form);
}
}
}
// Kurangi jumlah item
function kurangJumlah(btn, event) {
if (event) event.preventDefault();
var form = btn.closest('form');
var input = form.querySelector('input[name="jumlah"]');
var currentValue = parseInt(input.value);
// Nonaktifkan tombol jika sudah mencapai batas
var minusBtn = form.querySelector('button:first-of-type');
var plusBtn = form.querySelector('button:last-of-type');
if (currentValue > 1) {
// Kurangi nilai langsung
input.value = currentValue - 1;
// Update status tombol sebelum submit
plusBtn.disabled = false;
plusBtn.classList.remove('opacity-50');
if (currentValue - 1 <= 1) {
minusBtn.disabled = true;
minusBtn.classList.add('opacity-50');
}
// Update data-jumlah pada checkbox sebelum submit
var listItem = form.closest('li');
var checkbox = listItem.querySelector('.item-checkbox');
if (checkbox) {
checkbox.setAttribute('data-jumlah', currentValue - 1);
// Jika checkbox tercentang, perbarui total sementara untuk UI responsif
if (checkbox.checked) {
var hargaSatuan = parseInt(checkbox.getAttribute('data-harga-satuan') || 0);
var newTotalPrice = hargaSatuan * (currentValue - 1);
checkbox.setAttribute('data-price', newTotalPrice);
// Update total tampilan segera sebelum submit
updateTotal();
}
}
try {
// Simpan dengan cara tradisional via iframe
submitFormViaIframe(form);
} catch (e) {
console.error('Error submitFormViaIframe:', e);
// Gunakan metode alternatif jika iframe gagal
updateJumlahDirect(form);
}
}
}
// Fungsi alternatif untuk update jumlah dengan metode direct API
function updateJumlahDirect(form) {
// Tampilkan notifikasi
// showNotification('Menggunakan metode alternatif...', 'success');
// Ambil data dari form
var itemId = form.getAttribute('id').replace('form-update-', '');
var jumlahInput = form.querySelector('input[name="jumlah"]');
var jumlah = jumlahInput.value;
console.log('Update direct: ID=' + itemId + ', jumlah=' + jumlah);
// Tampilkan efek loading
var listItem = form.closest('li');
var totalElement = listItem.querySelector('.total-harga');
if (totalElement) {
totalElement.classList.add('opacity-50');
// totalElement.innerHTML = '<span class="inline-block animate-pulse">Menyimpan...</span>';
}
// Dapatkan CSRF token
var csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
// Buat FormData untuk request
var formData = new FormData();
formData.append('id', itemId);
formData.append('jumlah', jumlah);
formData.append('_token', csrfToken);
formData.append('_ts', new Date().getTime());
// Kirim dengan fetch API
fetch("{{ route('keranjang.update.direct') }}", {
method: 'POST',
headers: {
'X-CSRF-TOKEN': csrfToken,
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
},
body: formData
})
.then(response => {
console.log('Response status:', response.status);
if (!response.ok) {
console.error('Response error:', response.status, response.statusText);
throw new Error('Status: ' + response.status);
}
return response.json();
})
.then(data => {
console.log('Respons dari server:', data);
if (data.success) {
// Update UI
if (totalElement) {
totalElement.classList.remove('opacity-50');
totalElement.innerHTML = 'Rp ' + formatRupiah(data.data.total_harga);
totalElement.classList.add('text-green-600');
// Hapus highlight setelah beberapa saat
setTimeout(function() {
totalElement.classList.remove('text-green-600');
}, 1000);
}
// Update data pada checkbox
var checkbox = listItem.querySelector('.item-checkbox');
if (checkbox) {
checkbox.setAttribute('data-price', data.data.total_harga);
checkbox.setAttribute('data-jumlah', data.data.jumlah);
// Update total jika checkbox dicentang
if (checkbox.checked) {
updateTotal();
}
}
// Perbarui nilai original
jumlahInput.dataset.originalValue = data.data.jumlah;
// Tampilkan notifikasi sukses
// showNotification('Jumlah berhasil diperbarui', 'success');
} else {
// Tampilkan pesan error
totalElement.classList.remove('opacity-50');
totalElement.innerHTML = 'Error';
// showNotification(data.message || 'Gagal memperbarui jumlah', 'error');
// Kembalikan nilai sebelumnya
jumlahInput.value = jumlahInput.dataset.originalValue || 1;
updateJumlahInput(jumlahInput);
}
})
.catch(error => {
console.error('Error:', error);
// Kembalikan tampilan ke normal
if (totalElement) {
totalElement.classList.remove('opacity-50');
totalElement.innerHTML = 'Error';
}
// Kembalikan nilai sebelumnya
jumlahInput.value = jumlahInput.dataset.originalValue || 1;
updateJumlahInput(jumlahInput);
// Tampilkan notifikasi error dan reload sebagai fallback terakhir
// showNotification('Gagal memperbarui jumlah. Halaman akan dimuat ulang.', 'error');
setTimeout(function() {
window.location.reload();
}, 2000);
});
}
// Fungsi untuk submit form via iframe tersembunyi
function submitFormViaIframe(form, onSubmitSuccess) {
// Tampilkan efek loading
var listItem = form.closest('li');
var totalElement = listItem.querySelector('.total-harga');
if (totalElement) {
totalElement.classList.add('opacity-50');
// totalElement.innerHTML = '<span class="inline-block animate-pulse">Menyimpan...</span>';
}
// Tambahkan waktu submit untuk menghindari cache
var timeStamp = new Date().getTime();
var uniqueField = document.createElement('input');
uniqueField.type = 'hidden';
uniqueField.name = '_ts';
uniqueField.value = timeStamp;
form.appendChild(uniqueField);
// Tambahkan flag untuk menunjukkan permintaan dari JavaScript
var jsField = document.createElement('input');
jsField.type = 'hidden';
jsField.name = 'is_js_request';
jsField.value = '1';
form.appendChild(jsField);
// Tambahkan CSRF token
var csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
var csrfField = document.createElement('input');
csrfField.type = 'hidden';
csrfField.name = '_token';
csrfField.value = csrfToken;
form.appendChild(csrfField);
// Tambahkan atau perbarui field _method dengan PUT
var methodField = form.querySelector('input[name="_method"]');
if (!methodField) {
methodField = document.createElement('input');
methodField.type = 'hidden';
methodField.name = '_method';
methodField.value = 'PUT';
form.appendChild(methodField);
} else {
methodField.value = 'PUT';
}
// Tandai item yang sedang diproses dengan atribut sementara
var listItem = form.closest('li');
if (listItem) {
listItem.setAttribute('data-processing', 'true');
}
// Cek apakah iframe untuk submit sudah ada
var iframeId = 'hidden-submit-frame-' + timeStamp;
var iframe = document.createElement('iframe');
iframe.setAttribute('id', iframeId);
iframe.setAttribute('name', iframeId);
iframe.style.display = 'none';
document.body.appendChild(iframe);
// Setup penanganan pesan dari iframe
window.addEventListener('message', function(event) {
if (event.data === 'update_success' || event.data === 'delete_success') {
console.log('Received success message from iframe:', event.data);
// Update UI jika sukses
if (onSuccessCallback) {
onSuccessCallback();
}
}
}, false);
// Variable untuk menyimpan callback
var onSuccessCallback = null;
// Timeout handler untuk menangani iframe yang tidak merespons
var timeoutId = setTimeout(function() {
console.error('Iframe timeout - no response received');
// Hapus iframe
if (iframe && iframe.parentNode) {
iframe.parentNode.removeChild(iframe);
}
// Coba dengan metode direct
console.log('Trying alternative update method...');
updateJumlahDirect(form);
}, 5000); // Tunggu 5 detik
// Tambahkan event listener untuk respons iframe
iframe.onload = function() {
// Batalkan timeout
clearTimeout(timeoutId);
// Ini akan dijalankan setelah iframe menerima respons
console.log('Iframe loaded, checking response...');
try {
// Coba dapatkan respons dari iframe
var iframeContent = iframe.contentDocument || iframe.contentWindow.document;
console.log('Iframe response received');
// Periksa respons untuk kesalahan
if (iframeContent.body.textContent.includes('403') ||
iframeContent.body.textContent.includes('Forbidden') ||
iframeContent.body.textContent.includes('error')) {
console.error('Error dari iframe:', iframeContent.body.textContent);
// Kirim ulang dengan metode direct
// showNotification('Terjadi kesalahan, mencoba metode alternatif...', 'error');
updateJumlahDirect(form);
return;
}
// Cari elemen terkait
var listItem = form.closest('li');
var totalElement = listItem.querySelector('.total-harga');
var checkbox = listItem.querySelector('.item-checkbox');
var jumlahInput = form.querySelector('input[name="jumlah"]');
// Menyiapkan callback untuk eksekusi
onSuccessCallback = function() {
if (jumlahInput && checkbox && totalElement) {
// Perbarui ke server kembali dengan submit normal untuk memastikan data tersimpan
setTimeout(function() {
// Perbarui ke server kembali dengan submit normal
var reconfirmForm = document.createElement('form');
reconfirmForm.method = 'POST';
reconfirmForm.action = form.getAttribute('action');
// Salin semua input dari form asli
var inputs = form.querySelectorAll('input');
for (var i = 0; i < inputs.length; i++) {
var input = document.createElement('input');
input.name = inputs[i].name;
input.value = inputs[i].value;
input.type = 'hidden';
reconfirmForm.appendChild(input);
}
// Tambahkan tanda bahwa ini adalah pengiriman kedua untuk konfirmasi
var confirmField = document.createElement('input');
confirmField.type = 'hidden';
confirmField.name = 'is_confirm_submit';
confirmField.value = '1';
reconfirmForm.appendChild(confirmField);
// Tambahkan CSRF token baru
var csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
var csrfInput = document.createElement('input');
csrfInput.type = 'hidden';
csrfInput.name = '_token';
csrfInput.value = csrfToken;
reconfirmForm.appendChild(csrfInput);
try {
// Kirim ke rute biasa tanpa menggunakan target iframe
document.body.appendChild(reconfirmForm);
reconfirmForm.submit();
// Tampilkan pesan notifikasi
// showNotification('Menyimpan perubahan...', 'success');
// Hitung total baru berdasarkan harga satuan dan jumlah baru
var hargaSatuan = parseInt(checkbox.getAttribute('data-harga-satuan') || 0);
var jumlah = parseInt(jumlahInput.value);
var totalHarga = hargaSatuan * jumlah;
// Update tampilan harga sementara
totalElement.classList.remove('opacity-50');
totalElement.innerHTML = 'Rp ' + formatRupiah(totalHarga);
totalElement.classList.add('text-green-600');
// Hapus highlight setelah beberapa saat
setTimeout(function() {
totalElement.classList.remove('text-green-600');
// Hapus tanda pemrosesan
if (listItem) {
listItem.removeAttribute('data-processing');
}
}, 1000);
// Update data pada checkbox
checkbox.setAttribute('data-price', totalHarga);
checkbox.setAttribute('data-jumlah', jumlah);
// Update total jika checkbox dicentang
if (checkbox.checked) {
updateTotal();
}
// Jalankan callback sukses jika ada
if (onSubmitSuccess) {
onSubmitSuccess();
}
} catch (submitError) {
console.error('Error saat mengirim form konfirmasi:', submitError);
updateJumlahDirect(form); // Coba dengan metode direct sebagai fallback
}
}, 500); // Tunggu 500ms sebelum mengirim form konfirmasi
}
};
// Eksekusi callback
onSuccessCallback();
} catch(e) {
console.error('Error processing iframe response:', e);
// Coba dengan metode alternatif
// showNotification('Terjadi kesalahan, menggunakan metode alternatif...', 'error');
updateJumlahDirect(form);
} finally {
// Hapus iframe setelah selesai
setTimeout(function() {
if (iframe && iframe.parentNode) {
iframe.parentNode.removeChild(iframe);
}
}, 1000);
}
};
try {
// Set target ke iframe tersembunyi
form.setAttribute('target', iframeId);
// Submit form
console.log('Submitting form to:', form.getAttribute('action'));
form.submit();
} catch (submitError) {
console.error('Error submitting form via iframe:', submitError);
clearTimeout(timeoutId);
// Hapus iframe jika ada error
if (iframe && iframe.parentNode) {
iframe.parentNode.removeChild(iframe);
}
// Coba dengan metode direct
updateJumlahDirect(form);
}
}
// Menampilkan error
function showError(element, originalText) {
if (element) {
element.classList.remove('opacity-50');
element.innerHTML = originalText;
element.classList.add('text-red-600');
setTimeout(function() {
element.classList.remove('text-red-600');
}, 2000);
}
// Tampilkan pesan error
alert('Gagal menyimpan perubahan. Silakan coba lagi.');
}
// Tampilkan modal hapus
function hapusTerpilih() {
var selectedCount = document.querySelectorAll('.item-checkbox:checked').length;
document.getElementById('delete-count').textContent = selectedCount;
// Kosongkan container untuk input hidden
var container = document.getElementById('delete-items-container');
container.innerHTML = '';
// Tambahkan ID item terpilih ke dalam form hapus
var checkboxes = document.querySelectorAll('.item-checkbox:checked');
for (var i = 0; i < checkboxes.length; i++) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'selected_items[]';
input.value = checkboxes[i].value;
container.appendChild(input);
}
// Tampilkan modal
document.getElementById('delete-modal').classList.remove('hidden');
}
// Tutup modal hapus
function tutupModal() {
document.getElementById('delete-modal').classList.add('hidden');
}
// Fungsi untuk melakukan checkout
function checkoutItems() {
// Periksa apakah ada item yang dipilih
var checkboxes = document.querySelectorAll('.item-checkbox:checked');
if (checkboxes.length === 0) {
alert('Pilih minimal satu item untuk checkout');
return false;
}
console.log('Memproses checkout untuk', checkboxes.length, 'item');
// Pastikan CSRF token tersedia
var csrfToken = refreshCsrfToken();
// Buat form dinamis untuk mengirimkan data
var form = document.createElement('form');
form.method = 'POST';
form.action = "{{ route('keranjang.checkout-selected') }}";
form.style.display = 'none';
// Tambahkan CSRF token
var csrfInput = document.createElement('input');
csrfInput.type = 'hidden';
csrfInput.name = '_token';
csrfInput.value = csrfToken;
form.appendChild(csrfInput);
// Tambahkan semua ID yang dipilih ke form beserta jumlahnya
for (var i = 0; i < checkboxes.length; i++) {
var checkbox = checkboxes[i];
var itemId = checkbox.value;
// Tambahkan ID item
var inputId = document.createElement('input');
inputId.type = 'hidden';
inputId.name = 'selected_items[]';
inputId.value = itemId;
form.appendChild(inputId);
// Ambil nilai jumlah dari input terkait
var listItem = checkbox.closest('li');
var jumlahInput = listItem.querySelector('input[name="jumlah"]');
var jumlah = jumlahInput ? jumlahInput.value : 1;
// Tambahkan jumlah item
var inputJumlah = document.createElement('input');
inputJumlah.type = 'hidden';
inputJumlah.name = 'jumlah[' + itemId + ']';
inputJumlah.value = jumlah;
form.appendChild(inputJumlah);
console.log('Checkout item:', itemId, 'jumlah:', jumlah);
}
// Tambahkan form ke body dan kirim
document.body.appendChild(form);
console.log('Form checkout dibuat, mengirimkan...');
form.submit();
return true;
}
// Inisialisasi status tombol tambah/kurang
function initButtonState() {
var forms = document.querySelectorAll('form[id^="form-update-"]');
forms.forEach(function(form) {
var input = form.querySelector('input[name="jumlah"]');
var maxStok = parseInt(form.querySelector('input[name="max_stok"]').value);
var currentValue = parseInt(input.value);
// Simpan nilai awal untuk referensi
input.dataset.originalValue = currentValue;
var minusBtn = form.querySelector('button:first-of-type');
var plusBtn = form.querySelector('button:last-of-type');
// Set status tombol kurang
if (currentValue <= 1) {
minusBtn.disabled = true;
minusBtn.classList.add('opacity-50');
} else {
minusBtn.disabled = false;
minusBtn.classList.remove('opacity-50');
}
// Set status tombol tambah
if (currentValue >= maxStok) {
plusBtn.disabled = true;
plusBtn.classList.add('opacity-50');
} else {
plusBtn.disabled = false;
plusBtn.classList.remove('opacity-50');
}
});
}
// Fungsi untuk memperbarui UI saat input jumlah diubah langsung
function updateJumlahInput(input) {
var form = input.closest('form');
var maxStok = parseInt(form.querySelector('input[name="max_stok"]').value);
var currentValue = parseInt(input.value) || 0;
// Validasi nilai minimum dan maksimum
if (currentValue < 1) currentValue = 1;
if (currentValue > maxStok) currentValue = maxStok;
// Update status tombol
var minusBtn = form.querySelector('button:first-of-type');
var plusBtn = form.querySelector('button:last-of-type');
minusBtn.disabled = (currentValue <= 1);
minusBtn.classList.toggle('opacity-50', currentValue <= 1);
plusBtn.disabled = (currentValue >= maxStok);
plusBtn.classList.toggle('opacity-50', currentValue >= maxStok);
// Update preview harga jika checkbox tercentang
var listItem = form.closest('li');
var checkbox = listItem.querySelector('.item-checkbox');
var totalElement = listItem.querySelector('.total-harga');
if (checkbox && checkbox.checked && totalElement) {
var hargaSatuan = parseInt(checkbox.getAttribute('data-harga-satuan') || 0);
var newTotalPrice = hargaSatuan * currentValue;
// Update atribut data-price pada checkbox
checkbox.setAttribute('data-price', newTotalPrice);
checkbox.setAttribute('data-jumlah', currentValue);
// Preview harga baru dengan efek 'calculating'
totalElement.innerHTML = '<span class="text-blue-500">Rp ' + formatRupiah(newTotalPrice) + '</span>';
// Update subtotal
updateTotal();
}
}
// Fungsi untuk validasi dan pembaruan final saat input kehilangan fokus
function validateAndUpdate(input) {
var form = input.closest('form');
var maxStok = parseInt(form.querySelector('input[name="max_stok"]').value);
var currentValue = parseInt(input.value) || 0;
// Validasi nilai
if (isNaN(currentValue) || currentValue < 1) {
input.value = 1;
currentValue = 1;
} else if (currentValue > maxStok) {
input.value = maxStok;
currentValue = maxStok;
}
// Update preview UI sebelum submit
updateJumlahInput(input);
// Jika nilai tidak berubah, tidak perlu submit
if (input.dataset.originalValue && parseInt(input.dataset.originalValue) === currentValue) {
console.log('Nilai tidak berubah, tidak perlu submit');
return;
}
// Tambahkan callback untuk memperbarui nilai originalValue setelah berhasil
var onSubmitSuccess = function() {
// Perbarui nilai originalValue setelah berhasil disimpan
input.dataset.originalValue = currentValue.toString();
console.log('Nilai originalValue diperbarui ke', currentValue);
};
try {
// Submit dengan form biasa via iframe
submitFormViaIframe(form, onSubmitSuccess);
} catch (e) {
console.error('Error saat submit form via iframe:', e);
// Gunakan metode direct sebagai fallback
updateJumlahDirect(form);
}
}
// Fungsi untuk memastikan CSRF token selalu tersedia
function refreshCsrfToken() {
// Cek apakah meta tag CSRF sudah ada
var metaTag = document.querySelector('meta[name="csrf-token"]');
if (!metaTag) {
// Jika tidak ada, tambahkan meta tag
metaTag = document.createElement('meta');
metaTag.setAttribute('name', 'csrf-token');
metaTag.setAttribute('content', '{{ csrf_token() }}');
document.head.appendChild(metaTag);
console.log('CSRF token meta tag ditambahkan');
}
return metaTag.getAttribute('content');
}
// Fungsi untuk menghapus item menggunakan AJAX
function hapusItem(btn) {
// Konfirmasi dulu
if (!confirm('Yakin ingin menghapus item ini?')) {
return;
}
var form = btn.closest('form');
var listItem = form.closest('li');
var itemId = form.querySelector('input[name="item_id"]').value;
console.log('Menghapus item dengan ID:', itemId);
// Tampilkan modal loading
listItem.classList.add('opacity-50');
// showNotification('Menghapus item ID ' + itemId + '...', 'success');
// Dapatkan CSRF token
var csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
console.log('CSRF Token:', csrfToken);
// Buat data payload sederhana
var payload = {
id: itemId,
timestamp: new Date().getTime()
};
console.log('Payload:', payload);
// Gunakan fetch API dengan mode debug
console.log('Mengirim request ke: {{ route("keranjang.hapus.direct") }}');
fetch("{{ route('keranjang.hapus.direct') }}", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-TOKEN': csrfToken,
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify(payload)
})
.then(response => {
console.log('Response status:', response.status);
if (!response.ok) {
console.error('Response error:', response.status, response.statusText);
// Jika gagal dengan JSON, coba dengan XMLHttpRequest alternative
console.log('Mencoba metode alternatif...');
hapusItemAlt(btn);
throw new Error('Status: ' + response.status);
}
return response.json();
})
.then(data => {
console.log('Respons dari server:', data);
if (data.success) {
// Animasi visual sebelum remove
listItem.style.height = listItem.offsetHeight + 'px';
setTimeout(function() {
listItem.style.height = '0';
listItem.style.opacity = '0';
listItem.style.padding = '0';
listItem.style.margin = '0';
listItem.style.overflow = 'hidden';
// Hapus elemen setelah animasi
setTimeout(function() {
listItem.remove();
updateTotal(); // Update subtotal setelah hapus
// Periksa apakah keranjang kosong
var items = document.querySelectorAll('.item-checkbox');
if (items.length === 0) {
// Berikan waktu untuk melihat notifikasi
setTimeout(function() {
window.location.reload();
}, 1000);
}
// Tampilkan notifikasi sukses
// showNotification('Item berhasil dihapus', 'success');
}, 300);
}, 10);
} else {
// Tampilkan pesan error
listItem.classList.remove('opacity-50');
// showNotification(data.message || 'Gagal menghapus item', 'error');
console.error('Error dari server:', data);
}
})
.catch(error => {
console.error('Error:', error);
// Kembalikan tampilan item ke normal jika metode alternatif juga gagal
// listItem.classList.remove('opacity-50');
// showNotification('Gagal menghapus item. Silakan coba lagi.', 'error');
});
}
// Fungsi alternatif untuk menghapus item dengan XMLHttpRequest (lebih kompatibel)
function hapusItemAlt(btn) {
// Jika dipanggil langsung (bukan dari hapusItem)
if (btn && !confirm('Yakin ingin menghapus item ini?')) {
return;
}
var form = btn.closest('form');
var listItem = form.closest('li');
var itemId = form.querySelector('input[name="item_id"]').value;
console.log('Menghapus item dengan ID (XMLHttpRequest):', itemId);
// showNotification('Mencoba hapus dengan metode alternatif...', 'success');
// Tampilkan loading effect jika belum
if (!listItem.classList.contains('opacity-50')) {
listItem.classList.add('opacity-50');
}
// Buat XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open('POST', '{{ route("keranjang.hapus.direct") }}', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader('X-CSRF-TOKEN', '{{ csrf_token() }}');
xhr.setRequestHeader('Accept', 'application/json');
// Format sebagai form data (bukan JSON) untuk kompatibilitas
var formData = new FormData();
formData.append('id', itemId);
formData.append('_ts', new Date().getTime());
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
console.log('Status XHR:', xhr.status);
console.log('Response XHR:', xhr.responseText);
var success = false;
var message = 'Terjadi kesalahan';
try {
if (xhr.responseText) {
var response = JSON.parse(xhr.responseText);
success = response.success;
message = response.message || message;
}
} catch (e) {
console.error('Error parsing response:', e);
}
if (xhr.status === 200 && success) {
// Animasi visual sebelum remove
listItem.style.height = listItem.offsetHeight + 'px';
setTimeout(function() {
listItem.style.height = '0';
listItem.style.opacity = '0';
listItem.style.padding = '0';
listItem.style.margin = '0';
listItem.style.overflow = 'hidden';
// Hapus elemen setelah animasi
setTimeout(function() {
listItem.remove();
updateTotal(); // Update subtotal setelah hapus
// Periksa apakah keranjang kosong
var items = document.querySelectorAll('.item-checkbox');
if (items.length === 0) {
setTimeout(function() {
window.location.reload();
}, 1000);
}
// showNotification('Item berhasil dihapus', 'success');
}, 300);
}, 10);
} else {
// Kembalikan tampilan item ke normal
listItem.classList.remove('opacity-50');
// showNotification(message || 'Gagal menghapus item', 'error');
}
}
};
xhr.onerror = function() {
console.error('Network Error');
listItem.classList.remove('opacity-50');
// showNotification('Gagal terhubung ke server', 'error');
};
// Kirim request
xhr.send(formData);
}
// Fungsi untuk menampilkan notifikasi
function showNotification(message, type) {
var notif = document.createElement('div');
notif.className = type === 'success' ? 'bg-green-500 text-white' : 'bg-red-500 text-white';
notif.style.padding = '10px 15px';
notif.style.borderRadius = '4px';
notif.style.position = 'fixed';
notif.style.bottom = '20px';
notif.style.right = '20px';
notif.style.zIndex = '9999';
notif.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';
notif.style.transition = 'all 0.3s ease';
notif.style.opacity = '0';
notif.style.transform = 'translateY(10px)';
notif.textContent = message;
document.body.appendChild(notif);
// Tampilkan dengan animasi
setTimeout(function() {
notif.style.opacity = '1';
notif.style.transform = 'translateY(0)';
}, 10);
// Hilangkan setelah beberapa detik
setTimeout(function() {
notif.style.opacity = '0';
notif.style.transform = 'translateY(10px)';
setTimeout(function() {
notif.remove();
}, 300);
}, 3000);
}
// Fungsi untuk submit form hapus terpilih via iframe
function submitDeleteSelected() {
var form = document.getElementById('delete-form');
var selectedCount = document.getElementById('delete-count').textContent;
// Cek/buat iframe untuk delete-selected
var iframe = document.getElementById('hidden-delete-selected-frame');
if (!iframe) {
iframe = document.createElement('iframe');
iframe.setAttribute('id', 'hidden-delete-selected-frame');
iframe.setAttribute('name', 'hidden-delete-selected-frame');
iframe.style.display = 'none';
document.body.appendChild(iframe);
// Tambahkan event listener untuk respons iframe
iframe.onload = function() {
// Sembunyikan modal
document.getElementById('delete-modal').classList.add('hidden');
// Refresh halaman setelah hapus berhasil
// Ini lebih mudah karena kita perlu menghapus banyak item
window.location.reload();
};
}
// Set target iframe
form.target = 'hidden-delete-selected-frame';
// Submit form
form.submit();
// Tampilkan pesan
// showNotification(selectedCount + ' item sedang dihapus...', 'success');
}
// Fungsi untuk debug user yang login
function checkCurrentUser() {
console.log('Checking current user...');
fetch('/debug-user')
.then(response => response.json())
.then(data => {
console.log('Current user data:', data);
// showNotification('User ID: ' + data.user_id + ', nama: ' + data.user_name, 'success');
})
.catch(error => {
console.error('Error checking user:', error);
// showNotification('Gagal mengambil data user', 'error');
});
}
// Verifikasi autentikasi
function verifyAuth() {
fetch("{{ route('keranjang.index') }}?verify=1", {
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
}
})
.then(response => {
// Jika mendapat 401 atau 403, artinya tidak terotentikasi
if (response.status === 401 || response.status === 403) {
// showNotification('Sesi Anda telah berakhir. Silakan login kembali.', 'error');
setTimeout(() => {
window.location.href = "{{ route('login') }}";
}, 2000);
return null;
}
return response.json();
})
.catch(error => {
console.error('Error verifikasi autentikasi:', error);
});
}
// Fungsi untuk tes metode update PUT
function testUpdateMethod() {
var firstForm = document.querySelector('form[id^="form-update-"]');
if (!firstForm) {
// showNotification('Tidak ada form update ditemukan', 'error');
return;
}
var url = firstForm.action;
var itemId = firstForm.getAttribute('id').replace('form-update-', '');
var currentValue = parseInt(firstForm.querySelector('input[name="jumlah"]').value);
console.log('Testing PUT method for item ID:', itemId);
// showNotification('Testing PUT method untuk item ID: ' + itemId, 'success');
// Clone form data
var formData = new FormData();
formData.append('jumlah', currentValue);
formData.append('_method', 'PUT');
formData.append('_token', document.querySelector('meta[name="csrf-token"]').getAttribute('content'));
// Menggunakan fetch dengan method POST + _method=PUT
fetch(url, {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
},
body: formData
})
.then(response => {
console.log('Response status:', response.status);
console.log('Response headers:', response.headers);
if (!response.ok) {
console.error('Response error:', response.status, response.statusText);
// showNotification('Error: ' + response.status + ' ' + response.statusText, 'error');
return null;
}
return response.json().catch(() => response.text());
})
.then(data => {
if (data) {
console.log('Response data:', data);
if (typeof data === 'object') {
// showNotification('Sukses: ' + (data.message || 'OK'), 'success');
} else {
// showNotification('Sukses dengan response text', 'success');
}
}
})
.catch(error => {
console.error('Error:', error);
// showNotification('Error: ' + error.message, 'error');
});
}
// Fungsi untuk tes metode update direct
function testDirectMethod() {
var firstForm = document.querySelector('form[id^="form-update-"]');
if (!firstForm) {
// showNotification('Tidak ada form update ditemukan', 'error');
return;
}
var itemId = firstForm.getAttribute('id').replace('form-update-', '');
var currentValue = parseInt(firstForm.querySelector('input[name="jumlah"]').value);
console.log('Testing direct update for item ID:', itemId);
// showNotification('Testing direct update untuk item ID: ' + itemId, 'success');
// Gunakan metode direct
var formData = new FormData();
formData.append('id', itemId);
formData.append('jumlah', currentValue);
formData.append('_token', document.querySelector('meta[name="csrf-token"]').getAttribute('content'));
fetch("{{ route('keranjang.update.direct') }}", {
method: 'POST',
headers: {
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
},
body: formData
})
.then(response => {
console.log('Response status:', response.status);
if (!response.ok) {
console.error('Response error:', response.status, response.statusText);
// showNotification('Error: ' + response.status + ' ' + response.statusText, 'error');
return null;
}
return response.json();
})
.then(data => {
if (data) {
console.log('Response data:', data);
// showNotification('Sukses: ' + (data.message || 'OK'), 'success');
}
})
.catch(error => {
console.error('Error:', error);
// showNotification('Error: ' + error.message, 'error');
});
}
// Fungsi untuk memverifikasi CSRF token
function verifyCSRF() {
var token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
console.log('CSRF token current value:', token);
// Buat request sederhana ke server untuk cek token
fetch("{{ route('keranjang.index') }}?verify=1", {
method: 'POST',
headers: {
'X-CSRF-TOKEN': token,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({ check: 'csrf-verification' })
})
.then(response => {
console.log('CSRF test response status:', response.status);
if (response.status === 419) {
// CSRF token mismatch
// showNotification('CSRF token tidak valid!', 'error');
// Muat ulang halaman untuk mendapatkan token baru
setTimeout(() => {
window.location.reload();
}, 2000);
return null;
} else if (response.ok) {
// showNotification('CSRF token valid: ' + token.substring(0, 8) + '...', 'success');
return response.json().catch(() => null);
} else {
// showNotification('Error: ' + response.status, 'error');
return null;
}
})
.then(data => {
if (data) {
console.log('CSRF test response data:', data);
}
})
.catch(error => {
console.error('CSRF verification error:', error);
// showNotification('CSRF error: ' + error.message, 'error');
});
}
// Sinkronisasi nilai jumlah dari form utama ke form fallback
function syncFallbackValue(itemId) {
var mainForm = document.getElementById('form-update-' + itemId);
var fallbackInput = document.getElementById('fallback-jumlah-' + itemId);
if (mainForm && fallbackInput) {
var jumlahInput = mainForm.querySelector('input[name="jumlah"]');
if (jumlahInput) {
fallbackInput.value = jumlahInput.value;
console.log('Nilai jumlah disinkronkan: ' + jumlahInput.value);
}
}
return true;
}
// Jalankan saat halaman dimuat
window.onload = function() {
// Periksa status autentikasi
verifyAuth();
// Pastikan CSRF token tersedia
refreshCsrfToken();
// Sembunyikan alert setelah 3 detik
setTimeout(function() {
var successAlert = document.getElementById('success-alert');
var errorAlert = document.getElementById('error-alert');
if (successAlert) successAlert.style.display = 'none';
if (errorAlert) errorAlert.style.display = 'none';
}, 3000);
// Verifikasi apakah halaman di-reload
var wasReloaded = performance.navigation.type === 1;
if (wasReloaded) {
// Tunggu sedikit agar UI selesai dimuat
setTimeout(function() {
// Ambil data dari server untuk memastikan konsistensi
verifikasiDataKeranjang(true);
console.log('Halaman di-reload, memverifikasi data keranjang...');
}, 500);
}
// Setup event listener untuk pesan dari iframe
window.addEventListener('message', function(event) {
if (event.data === "delete_success") {
console.log('Penghapusan berhasil');
} else if (event.data === "delete_error") {
console.error('Penghapusan gagal');
// showNotification('Gagal menghapus item. Halaman akan dimuat ulang.', 'error');
setTimeout(function() {
window.location.reload();
}, 2000);
} else if (event.data === "update_success") {
console.log('Update berhasil');
} else if (event.data === "update_error") {
console.error('Update gagal');
// showNotification('Gagal mengubah jumlah. Halaman akan dimuat ulang.', 'error');
setTimeout(function() {
window.location.reload();
}, 2000);
}
});
// Inisialisasi total
updateTotal();
// Inisialisasi status tombol tambah/kurang
initButtonState();
// Tambahan: Hapus localStorage setelah halaman keranjang dimuat
// Ini mencegah data checkout tersimpan setelah kembali ke halaman keranjang
localStorage.removeItem('selected_keranjang_items');
// Verifikasi data keranjang dari server setiap 30 detik
// untuk memastikan UI konsisten dengan data di database
setInterval(verifikasiDataKeranjang, 30000);
};
// Fungsi untuk memverifikasi data keranjang dengan server
function verifikasiDataKeranjang(isReload) {
// Jika ada form yang sedang diproses, tunda verifikasi
if (document.querySelector('[data-processing="true"]') || document.querySelector('.processing-delete')) {
console.log('Ada operasi yang sedang berlangsung, menunda verifikasi data keranjang');
return;
}
// Cek apakah ada perubahan yang belum disimpan
var isFormChanged = false;
var forms = document.querySelectorAll('form[id^="form-update-"]');
forms.forEach(function(form) {
var input = form.querySelector('input[name="jumlah"]');
if (input && input.dataset.originalValue && input.value !== input.dataset.originalValue) {
isFormChanged = true;
}
});
if (isFormChanged) {
console.log('Ada perubahan formulir yang belum disimpan, menunda verifikasi data keranjang');
return;
}
// Gunakan fetch API untuk mendapatkan data terbaru dari server
fetch("{{ route('keranjang.index') }}?verify=1&_ts=" + new Date().getTime(), {
method: 'GET',
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => {
console.log('Data keranjang dari server:', data);
// Sinkronkan data dengan UI
if (data.items && data.items.length > 0) {
data.items.forEach(function(item) {
// Cari form untuk item ini
var form = document.getElementById('form-update-' + item.id);
if (form) {
var jumlahInput = form.querySelector('input[name="jumlah"]');
if (jumlahInput && parseInt(jumlahInput.value) !== item.jumlah) {
console.log('Sinkronisasi item ' + item.id + ': UI=' + jumlahInput.value + ', Server=' + item.jumlah);
// Update nilai input
jumlahInput.value = item.jumlah;
jumlahInput.dataset.originalValue = item.jumlah;
// Perbarui total harga item
var listItem = form.closest('li');
var totalElement = listItem.querySelector('.total-harga');
if (totalElement) {
totalElement.innerHTML = 'Rp ' + formatRupiah(item.total_harga);
}
// Perbarui data pada checkbox
var checkbox = listItem.querySelector('.item-checkbox');
if (checkbox) {
checkbox.setAttribute('data-price', item.total_harga);
checkbox.setAttribute('data-jumlah', item.jumlah);
// Update total jika checkbox dicentang
if (checkbox.checked) {
updateTotal();
}
}
// Perbarui status tombol tambah/kurang
initButtonState();
// Tampilkan notifikasi jika ini adalah reload
if (isReload) {
// showNotification('Data keranjang telah disinkronkan dengan server', 'success');
}
}
}
});
// Cek apakah ada item yang hilang di server
var serverItemIds = data.items.map(item => item.id);
var uiItems = document.querySelectorAll('.item-checkbox');
uiItems.forEach(function(checkbox) {
var itemId = parseInt(checkbox.value);
if (!serverItemIds.includes(itemId)) {
// Item tidak ada di server, hapus dari UI
console.log('Item ' + itemId + ' tidak ditemukan di server, menghapus dari UI');
var listItem = checkbox.closest('li');
if (listItem) {
// Animasi hapus
listItem.style.height = listItem.offsetHeight + 'px';
setTimeout(function() {
listItem.style.height = '0';
listItem.style.opacity = '0';
listItem.style.padding = '0';
listItem.style.margin = '0';
listItem.style.overflow = 'hidden';
// Hapus elemen setelah animasi
setTimeout(function() {
listItem.remove();
updateTotal(); // Update subtotal setelah hapus
// Tampilkan notifikasi jika ini adalah reload
if (isReload) {
// showNotification('Beberapa item yang tidak valid telah dihapus', 'success');
}
// Periksa apakah keranjang kosong
var remainingItems = document.querySelectorAll('.item-checkbox');
if (remainingItems.length === 0) {
// Reload halaman untuk menampilkan UI keranjang kosong
window.location.reload();
}
}, 300);
}, 10);
}
}
});
}
})
.catch(error => {
console.error('Error saat memverifikasi data keranjang:', error);
});
}
</script>
<div class="container px-4 py-8 mx-auto">
<div class="flex items-center justify-between mb-6">
<h1 class="text-2xl font-bold text-gray-800">Keranjang Belanja</h1>
<div class="flex space-x-2">
<!-- <button type="button" onclick="checkCurrentUser()" class="px-4 py-2 text-sm font-medium text-white bg-purple-500 rounded-md hover:bg-purple-600">
<i class="fas fa-user-check mr-2"></i>Cek User
</button> -->
<a href="{{ route('barang.index') }}" class="px-4 py-2 text-sm font-medium text-white bg-blue-500 rounded-md hover:bg-blue-600">
<i class="fas fa-shopping-basket mr-2"></i>Lanjut Belanja
</a>
@if(count($items) > 0)
<form action="{{ route('keranjang.kosongkan') }}" method="POST" class="inline" onsubmit="return confirm('Yakin ingin mengosongkan keranjang?')">
@csrf
@method('DELETE')
<button type="submit" class="px-4 py-2 text-sm font-medium text-white bg-red-500 rounded-md hover:bg-red-600">
<i class="fas fa-trash mr-2"></i>Kosongkan
</button>
</form>
@endif
</div>
</div>
@if(session('success'))
<div class="relative px-4 py-3 mb-4 text-green-700 bg-green-100 border border-green-400 rounded" id="success-alert">
<span class="block sm:inline">{{ session('success') }}</span>
<button type="button" class="absolute top-0 right-0 px-4 py-3" onclick="this.parentElement.style.display='none'">
<i class="fas fa-times"></i>
</button>
</div>
@endif
@if(session('error'))
<div class="relative px-4 py-3 mb-4 text-red-700 bg-red-100 border border-red-400 rounded" id="error-alert">
<span class="block sm:inline">{{ session('error') }}</span>
<button type="button" class="absolute top-0 right-0 px-4 py-3" onclick="this.parentElement.style.display='none'">
<i class="fas fa-times"></i>
</button>
</div>
@endif
<!-- <div class="mb-4 p-4 bg-gray-100 rounded-lg">
<h3 class="text-sm font-semibold text-gray-700 mb-2">Opsi Debug</h3>
<div class="flex space-x-2">
<button type="button" onclick="checkCurrentUser()" class="px-2 py-1 text-xs font-medium text-white bg-purple-500 rounded hover:bg-purple-600">
Cek User
</button>
<button type="button" onclick="testUpdateMethod()" class="px-2 py-1 text-xs font-medium text-white bg-blue-500 rounded hover:bg-blue-600">
Test PUT Method
</button>
<button type="button" onclick="testDirectMethod()" class="px-2 py-1 text-xs font-medium text-white bg-green-500 rounded hover:bg-green-600">
Test Direct Update
</button>
<button type="button" onclick="verifyCSRF()" class="px-2 py-1 text-xs font-medium text-white bg-orange-500 rounded hover:bg-orange-600">
Cek CSRF
</button>
</div>
</div> -->
@if(count($items) > 0)
<div id="checkout-container">
@csrf
<div id="selected-items-container"></div>
<div class="bg-white rounded-xl shadow-md overflow-hidden mb-6">
<div class="p-6">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center">
<input type="checkbox" id="select-all" onclick="pilihSemua()" class="w-5 h-5 rounded accent-[#2C7A7B] cursor-pointer">
<label for="select-all" class="ml-2 text-sm font-medium text-gray-700 cursor-pointer">Pilih Semua</label>
</div>
<button type="button" id="delete-selected" class="hidden text-sm font-medium text-red-600 hover:text-red-800" onclick="hapusTerpilih()">
<i class="fas fa-trash mr-1"></i> Hapus Terpilih
</button>
</div>
<div class="flow-root">
<ul class="-my-6 divide-y divide-gray-200">
@foreach($items as $item)
<li class="py-6 flex item-li">
<div class="flex items-center pr-4">
<input type="checkbox" name="selected_items[]" value="{{ $item->id }}" data-price="{{ $item->total_harga }}" data-jumlah="{{ $item->jumlah }}" data-harga-satuan="{{ $item->barang->harga }}" onclick="updateTotal()" class="item-checkbox w-5 h-5 rounded accent-[#2C7A7B] cursor-pointer">
</div>
<div class="flex-shrink-0 w-24 h-24 rounded-md overflow-hidden border border-gray-200">
@if($item->barang->gambar)
<img src="{{ Storage::url($item->barang->gambar) }}" alt="{{ $item->barang->nama_barang }}" class="w-full h-full object-cover">
@else
<div class="w-full h-full bg-gray-200 flex items-center justify-center">
<span class="text-gray-400">No Image</span>
</div>
@endif
</div>
<div class="ml-4 flex-1 flex flex-col">
<div>
<div class="flex justify-between text-base font-medium text-gray-900">
<h3>
<a href="{{ route('barang.show', $item->barang) }}">{{ $item->barang->nama_barang }}</a>
</h3>
<p class="ml-4 total-harga">Rp {{ number_format($item->total_harga, 0, ',', '.') }}</p>
</div>
<p class="mt-1 text-sm text-gray-500">Harga Satuan: Rp {{ number_format($item->barang->harga, 0, ',', '.') }}</p>
</div>
<div class="flex-1 flex items-end justify-between text-sm">
<div class="flex items-center">
<span class="text-gray-500 mr-3">Jumlah:</span>
<form action="{{ route('keranjang.update', $item) }}" method="POST" class="flex items-center" id="form-update-{{ $item->id }}">
@csrf
@method('PUT')
<input type="hidden" name="_method" value="PUT">
<button type="button" onclick="kurangJumlah(this, event)" class="p-1 text-gray-500 hover:bg-gray-100 rounded-md transition-opacity">
<i class="fas fa-minus"></i>
</button>
<input type="number" name="jumlah" value="{{ $item->jumlah }}" min="1" max="{{ $item->barang->stok }}"
class="mx-2 w-16 text-center border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
oninput="updateJumlahInput(this)" onchange="validateAndUpdate(this)">
<input type="hidden" name="max_stok" value="{{ $item->barang->stok }}">
<button type="button" onclick="tambahJumlah(this, event)" class="p-1 text-gray-500 hover:bg-gray-100 rounded-md transition-opacity">
<i class="fas fa-plus"></i>
</button>
</form>
<!-- <div class="ml-2 flex items-center space-x-2">
<button type="button" onclick="updateJumlahDirect(document.getElementById('form-update-{{ $item->id }}'))"
class="px-2 text-sm text-blue-600 hover:text-blue-800" title="Update langsung">
<i class="fas fa-sync-alt"></i>
</button>
<form action="{{ route('keranjang.update.fallback') }}" method="POST" style="display:inline;">
@csrf
<input type="hidden" name="id" value="{{ $item->id }}">
<input type="hidden" name="jumlah" id="fallback-jumlah-{{ $item->id }}" value="{{ $item->jumlah }}">
<button type="submit" class="px-2 text-sm text-green-600 hover:text-green-800"
title="Update fallback" onclick="syncFallbackValue('{{ $item->id }}')">
<i class="fas fa-check"></i>
</button>
</form>
</div> -->
</div>
<div class="flex">
<form action="{{ route('keranjang.hapus.post', $item) }}" method="POST" class="delete-form" novalidate onsubmit="return false;">
@csrf
<!-- Tambahkan token csrf secara eksplisit -->
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<!-- Tambahkan item ID untuk metode hapus manual -->
<input type="hidden" name="item_id" value="{{ $item->id }}">
<div class="flex space-x-2">
<button type="button" onclick="hapusItem(this)" class="font-medium text-red-600 hover:text-red-500">
<i class="fas fa-trash mr-1"></i> Hapus
</button>
<!-- <button type="button" onclick="hapusItemAlt(this)" class="font-medium text-orange-600 hover:text-orange-500" title="Metode alternatif">
<i class="fas fa-trash-alt"></i>
</button>
<form action="{{ route('keranjang.hapus.fallback') }}" method="POST" style="display:inline;" onsubmit="return confirm('Yakin ingin menghapus dengan metode fallback?');">
@csrf
<input type="hidden" name="id" value="{{ $item->id }}">
<button type="submit" class="font-medium text-green-600 hover:text-green-500" title="Metode fallback">
<i class="fas fa-check"></i>
</button>
</form> -->
</div>
</form>
</div>
</div>
</div>
</li>
@endforeach
</ul>
</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-md overflow-hidden">
<div class="p-6">
<div class="flex justify-between text-base font-medium text-gray-900 mb-4">
<p>Subtotal (<span id="selected-count">0</span> item)</p>
<p>Rp <span id="selected-total">0</span></p>
</div>
<div class="mt-6">
<button href="{{ route('keranjang.checkout-selected') }}" type="button" id="checkout-button" onclick="checkoutItems()" disabled class="w-full flex justify-center items-center px-6 py-3 border border-transparent rounded-md shadow-sm text-base font-medium text-white bg-gray-400 cursor-not-allowed">
Checkout (<span id="checkout-count">0</span>)
</button>
</div>
<div class="mt-4 flex justify-center text-sm text-gray-500">
<p>
<a href="{{ route('barang.index') }}" class="text-[#2C7A7B] font-medium hover:text-[#1C6B6B]">
<i class="fas fa-arrow-left mr-2"></i>Lanjutkan Belanja
</a>
</p>
</div>
</div>
</div>
</div>
@else
<div class="bg-white p-6 rounded-xl shadow-md text-center">
<div class="flex justify-center mb-4">
<div class="w-24 h-24 text-gray-300">
<i class="fas fa-shopping-cart text-6xl"></i>
</div>
</div>
<h3 class="text-lg font-medium text-gray-800 mb-2">Keranjang Anda Kosong</h3>
<p class="text-gray-500 mb-6">Anda belum menambahkan barang apapun ke keranjang</p>
<a href="{{ route('barang.index') }}" class="inline-flex items-center px-4 py-2 bg-[#2C7A7B] text-white rounded-lg hover:bg-[#1C6B6B] transition-colors duration-200">
<i class="fas fa-shopping-bag mr-2"></i>Mulai Belanja
</a>
</div>
@endif
</div>
<!-- Modal Konfirmasi Hapus -->
<div id="delete-modal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div class="bg-white rounded-lg p-6 max-w-md w-full mx-4">
<h3 class="text-lg font-semibold text-gray-900 mb-4">Konfirmasi Hapus</h3>
<p class="text-gray-600 mb-6">Apakah Anda yakin ingin menghapus <span id="delete-count">0</span> item terpilih?</p>
<div class="flex justify-end space-x-3">
<button type="button" onclick="tutupModal()" class="px-4 py-2 bg-gray-300 text-gray-800 rounded-md hover:bg-gray-400">
Batal
</button>
<form action="{{ route('keranjang.hapus-selected') }}" method="POST" id="delete-form">
@csrf
@method('DELETE')
<div id="delete-items-container"></div>
<button type="button" onclick="submitDeleteSelected()" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700">
Hapus
</button>
</form>
</div>
</div>
</div>
@endsection