/** * Cart Functionality * Handle cart interactions in the POS system */ $(document).ready(function() { // Setup quantity controls setupQuantityControls(); // Setup cart item deletion confirmation setupCartDeletionConfirmation(); // Setup cash input handling setupCashInput(); // Setup quick cash buttons setupQuickCashButtons(); // Setup checkout form setupCheckoutForm(); // Initialize cart scrolling initializeCartScrolling(); // Handle multi-select functionality setupMultiSelectMode(); // Handle window resize to adjust cart height $(window).on('resize', function() { initializeCartScrolling(); }); // Handle form submission with enter key setupQuantityFormSubmission(); }); /** * Setup quantity controls for increment and decrement * This function handles the +/- buttons for item quantities */ function setupQuantityControls() { // Remove any existing event handlers to prevent duplicates $('.quantity-btn.increment, .quantity-btn.decrement').off('click'); // Setup increment button $('.quantity-btn.increment').on('click', function() { const quantityField = $(this).siblings('.quantity-field'); const currentValue = parseInt(quantityField.val()) || 0; const maxStock = parseInt(quantityField.data('max-stock')) || 99; // Only increment if below max stock if (currentValue < maxStock) { quantityField.val(currentValue + 1); } }); // Setup decrement button $('.quantity-btn.decrement').on('click', function() { const quantityField = $(this).siblings('.quantity-field'); const currentValue = parseInt(quantityField.val()) || 0; // Only decrement if above 1 if (currentValue > 1) { quantityField.val(currentValue - 1); } }); // Handle manual input validation $('.quantity-field').on('change', function() { let value = parseInt($(this).val()) || 0; const maxStock = parseInt($(this).data('max-stock')) || 99; // Ensure value is between 1 and max stock if (value < 1) value = 1; if (value > maxStock) value = maxStock; $(this).val(value); }); } /** * Setup cart item deletion confirmation * This function handles the delete button clicks and confirmation modal */ function setupCartDeletionConfirmation() { // Remove any existing event handlers to prevent duplicates $('.delete-cart-item').off('click'); // Setup delete button click event $('.delete-cart-item').on('click', function(e) { e.preventDefault(); const itemIndex = $(this).data('index'); // Set the confirmation button's href $('#confirm-delete-btn').attr('href', 'index.php?remove_item=' + itemIndex); // Show the confirmation modal if (typeof bootstrap !== 'undefined' && $('#deleteConfirmModal').length) { const deleteModal = new bootstrap.Modal(document.getElementById('deleteConfirmModal')); deleteModal.show(); } else { // Fallback if Bootstrap modal isn't available if (confirm('Apakah Anda yakin ingin menghapus item ini dari keranjang Anda?')) { window.location.href = 'index.php?remove_item=' + itemIndex; } } }); // Setup confirm delete button $('#confirm-delete-btn').on('click', function() { // Button href is already set above }); } /** * Setup quantity form submission on enter key */ function setupQuantityFormSubmission() { $('.quantity-field').on('keydown', function(e) { if (e.keyCode === 13) { e.preventDefault(); $(this).closest('form').submit(); } }); } /** * Setup cash input handling with number formatting */ function setupCashInput() { const cashInput = $('#cash-amount'); const hiddenCashAmount = $('#hidden-cash-amount'); // Initialize change amount display updateChangeDisplay(); // Handle cash input change cashInput.on('input', function() { // Remove non-numeric characters except decimal point let value = $(this).val().replace(/[^\d]/g, ''); // Parse to integer const numericValue = parseInt(value) || 0; // Format with thousand separator $(this).val(formatNumber(numericValue)); // Update hidden field with numeric value hiddenCashAmount.val(numericValue); // Update change display updateChangeDisplay(); }); // Make sure initial value is formatted const initialValue = parseInt(cashInput.val().replace(/[^\d]/g, '')) || 0; cashInput.val(formatNumber(initialValue)); hiddenCashAmount.val(initialValue); } /** * Update change display based on current cash amount and total */ function updateChangeDisplay() { const cashInput = $('#cash-amount'); const changeDisplay = $('#change-amount'); const changeContainer = $('#change-container'); const hiddenCashAmount = $('#hidden-cash-amount'); const hiddenChangeAmount = $('#hidden-change-amount'); // Get total from the displayed value or use 0 if not available const totalText = $('.total-value h6').text(); const totalAmount = parseFloat(totalText.replace(/[^\d]/g, '')) || 0; // Get cash value from hidden field or parse from display let cashValue = parseFloat(hiddenCashAmount.val()) || 0; if (cashValue === 0) { // Try to parse from display as fallback cashValue = parseFloat(cashInput.val().replace(/[^\d.,]/g, '').replace(/\./g, '').replace(',', '.')) || 0; hiddenCashAmount.val(cashValue); } // Calculate change const change = cashValue - totalAmount; // Update hidden field for change amount hiddenChangeAmount.val(Math.max(0, change)); // Format and display if (change >= 0 && totalAmount > 0) { changeDisplay.text('Rp. ' + formatNumber(change)); changeContainer.show(); } else { changeContainer.hide(); } } /** * Setup quick cash buttons */ function setupQuickCashButtons() { $('.quick-cash').on('click', function() { const value = $(this).data('value'); $('#cash-amount').val(formatNumber(value)); $('#hidden-cash-amount').val(value); updateChangeDisplay(); }); } /** * Setup checkout form validation */ function setupCheckoutForm() { $('#checkout-form').on('submit', function(e) { const cashAmount = parseFloat($('#hidden-cash-amount').val()) || 0; const totalText = $('.total-value h6').text(); const totalAmount = parseFloat(totalText.replace(/[^\d]/g, '')) || 0; if (cashAmount < totalAmount) { e.preventDefault(); alert('Jumlah tunai harus sama dengan atau lebih besar dari jumlah total.'); return false; } // Disable button to prevent double submission $(this).find('button[type="submit"]').prop('disabled', true).html(' Memproses...'); return true; }); } /** * Initialize scrolling behavior for cart */ function initializeCartScrolling() { // Make sure product table has correct max height const windowHeight = $(window).height(); const headerHeight = $('.order-list').outerHeight() || 0; const cardHeaderHeight = $('.card-order .card-body:first-of-type').outerHeight() || 0; const cardFooterHeight = $('.card-order .card-body:last-of-type').outerHeight() || 0; const availableHeight = windowHeight - headerHeight - cardHeaderHeight - cardFooterHeight - 120; // 120px buffer // Set max height for scrollable area $('.product-table').css('max-height', availableHeight + 'px'); } /** * Setup multi-select mode for products */ function setupMultiSelectMode() { let isMultiSelectMode = false; let selectedProducts = []; // Toggle multi-select mode $('.productset').on('long-press', function() { if (!isMultiSelectMode) { enterMultiSelectMode(); // Select the long-pressed product $(this).addClass('selected'); const productId = $(this).data('product-id'); selectedProducts.push(productId); updateSelectedCount(); } }); // Simulate long press on desktop let pressTimer; $('.productset').on('mousedown', function() { const $this = $(this); pressTimer = setTimeout(function() { if (!isMultiSelectMode) { enterMultiSelectMode(); // Select the long-pressed product $this.addClass('selected'); const productId = $this.data('product-id'); selectedProducts.push(productId); updateSelectedCount(); } }, 800); // Long press threshold of 800ms }).on('mouseup mouseleave', function() { clearTimeout(pressTimer); }); // Handle product click in multi-select mode $('.productset').on('click', function(e) { if (isMultiSelectMode) { e.preventDefault(); e.stopPropagation(); const $this = $(this); const productId = $this.data('product-id'); if ($this.hasClass('selected')) { // Deselect $this.removeClass('selected'); selectedProducts = selectedProducts.filter(id => id !== productId); } else { // Select $this.addClass('selected'); selectedProducts.push(productId); } updateSelectedCount(); } }); // Cancel selection $('#cancel-selection').on('click', function() { exitMultiSelectMode(); }); // Add selected products to cart $('#add-selected-to-cart').on('click', function() { if (selectedProducts.length > 0) { // Show loading state $(this).prop('disabled', true).html(' Menambahkan...'); // Submit selected products $.ajax({ url: 'index.php', type: 'POST', data: { product_ids: selectedProducts }, success: function() { window.location.reload(); }, error: function() { alert('Gagal menambahkan produk ke keranjang. Silakan coba lagi.'); $('#add-selected-to-cart').prop('disabled', false).text('Tambahkan ke keranjang'); } }); } }); // Functions to enter/exit multi-select mode function enterMultiSelectMode() { isMultiSelectMode = true; selectedProducts = []; $('.multi-select-toolbar').addClass('active'); $('.selected-count').text('0 produk terseleksi'); // Disable normal click actions on products $('.add-single-form button[type="submit"]').prop('disabled', true); } function exitMultiSelectMode() { isMultiSelectMode = false; selectedProducts = []; $('.multi-select-toolbar').removeClass('active'); $('.productset').removeClass('selected'); // Re-enable normal click actions $('.add-single-form button[type="submit"]').prop('disabled', false); } function updateSelectedCount() { $('.selected-count').text(selectedProducts.length + ' produk terseleksi'); // Only enable add button if products are selected if (selectedProducts.length > 0) { $('#add-selected-to-cart').prop('disabled', false); } else { $('#add-selected-to-cart').prop('disabled', true); } } } /** * Format number with thousand separator */ function formatNumber(number) { return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "."); }