AyulaPOS/views/transaction/transaction.js

633 lines
22 KiB
JavaScript

/**
* Ayula Store POS System
* Main JavaScript file for transaction page functionality
*/
$(document).ready(function() {
// Initialize globals
initializeGlobals();
// Setup event handlers
setupEventHandlers();
// Initialize UI components
initializeUI();
// Check and update the "Clear All" button state on page load
updateClearCartButtonInitialState();
// Make sure cart functionality is properly initialized
ensureCartFunctionalityInitialized();
});
/**
* Make sure cart functionality is properly initialized
* This acts as a safety measure to ensure critical functions are available
*/
function ensureCartFunctionalityInitialized() {
// Check if key functions exist, if not define them
if (typeof setupQuantityControls !== 'function') {
console.log('Initializing missing cart functions...');
// Define quantity controls if missing
window.setupQuantityControls = function() {
// 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);
});
// Enable form submission with enter key
$('.quantity-field').on('keydown', function(e) {
if (e.keyCode === 13) {
e.preventDefault();
$(this).closest('form').submit();
}
});
};
// Define cart deletion confirmation if missing
window.setupCartDeletionConfirmation = function() {
// 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;
}
}
});
};
// Initialize these functions right away
setupQuantityControls();
setupCartDeletionConfirmation();
console.log('Cart functions initialized');
}
}
/**
* Initialize global variables and state
*/
function initializeGlobals() {
// Variables to track selected products
window.selectedProducts = [];
window.multiSelectToolbar = $('.multi-select-toolbar');
// Store product stock information
window.productStock = {};
$('.productset').each(function() {
const productId = $(this).data('product-id');
const stockText = $(this).find('.productsetimg h6').text();
const stockValue = parseInt(stockText.replace('Stok: ', '')) || 0;
window.productStock[productId] = stockValue;
});
}
/**
* Check and update the "Clear All" button state on page load
*/
function updateClearCartButtonInitialState() {
const cartItemsCount = $('.product-lists').length;
console.log('Initial cart items count:', cartItemsCount);
// Get the clear cart button
const clearCartBtn = $('#clear-cart-btn');
if (cartItemsCount > 0) {
// Enable the clear cart button
clearCartBtn.attr('href', 'javascript:void(0);')
.removeClass('disabled')
.css({
'opacity': '1',
'cursor': 'pointer'
})
.off('click')
.on('click', function(e) {
e.preventDefault();
if (typeof bootstrap !== 'undefined' && $('#clearCartModal').length) {
try {
const clearModal = new bootstrap.Modal(document.getElementById('clearCartModal'));
clearModal.show();
} catch (error) {
console.log('Modal error, using fallback:', error);
if (confirm('Apakah Anda yakin ingin menghapus semua item dari keranjang Anda?')) {
window.location.href = 'index.php?clear_cart=1';
}
}
} else {
if (confirm('Apakah Anda yakin ingin menghapus semua item dari keranjang Anda?')) {
window.location.href = 'index.php?clear_cart=1';
}
}
});
console.log('Clear cart button initially enabled');
} else {
// Disable the clear cart button
clearCartBtn.attr('href', '#')
.addClass('disabled')
.css({
'opacity': '0.5',
'cursor': 'not-allowed'
})
.off('click');
console.log('Clear cart button initially disabled');
}
}
/**
* Setup all event handlers for the page
*/
function setupEventHandlers() {
// Product card selection
setupProductSelection();
// Toolbar actions
setupToolbarActions();
// Setup modal buttons properly
setupModalButtons();
}
/**
* Setup modal buttons for all modals
*/
function setupModalButtons() {
// Delete confirmation modal
$('#deleteConfirmModal').on('show.bs.modal', function (event) {
// Make sure the confirm delete button is functional
$('#confirm-delete-btn').off('click').on('click', function(e) {
// Use the href attribute for navigation
const href = $(this).attr('href');
if (href) {
window.location.href = href;
}
});
});
// Clear cart modal
$('#clearCartModal').on('show.bs.modal', function (event) {
// Make sure cancel button closes the modal
$('#cancel-clear-cart').off('click').on('click', function() {
const clearModal = bootstrap.Modal.getInstance(document.getElementById('clearCartModal'));
if (clearModal) {
clearModal.hide();
}
});
// Make sure confirm button navigates to clear cart action
$('#confirm-clear-cart').off('click').on('click', function() {
window.location.href = 'index.php?clear_cart=1';
});
});
}
/**
* Initialize UI components
*/
function initializeUI() {
// Hide all check marks initially
$('.check-product i').hide();
// Trigger toggle button click to activate it when page loads
setTimeout(function() {
$("#toggle_btn").trigger('click');
}, 100);
// Focus search field when search icon is clicked
$('.responsive-search').on('click', function() {
setTimeout(function() {
$('input[name="search"]').focus();
}, 100);
});
// Focus the page header search field on click
$('.product-search-form input[name="search"]').on('click', function() {
$(this).focus();
});
// Enable live search functionality
setupLiveSearch();
// Enable AJAX category navigation
setupCategoryNavigation();
// Initialize cash payment functionality
setupCashPayment();
}
/**
* Setup product selection functionality
*/
function setupProductSelection() {
// Click on product card to toggle selection
$('.productset').on('click', function(e) {
// Only handle clicks on the card itself, not buttons or links inside
if ($(e.target).closest('button, a, form').length === 0) {
const productId = $(this).data('product-id');
const checkbox = $(this).find('.product-checkbox');
const isChecked = checkbox.prop('checked');
console.log('Clicked product ID:', productId);
// Toggle checkbox
checkbox.prop('checked', !isChecked);
if (!isChecked) {
// Add to selected list and highlight
window.selectedProducts.push(productId);
$(this).addClass('selected');
$(this).find('.check-product i').show();
} else {
// Remove from selected list and unhighlight
window.selectedProducts = window.selectedProducts.filter(id => id !== productId);
$(this).removeClass('selected');
$(this).find('.check-product i').hide();
}
console.log('Selected products:', window.selectedProducts);
updateToolbar();
}
});
}
/**
* Setup toolbar action buttons
*/
function setupToolbarActions() {
// Cancel selection button
$('#cancel-selection').on('click', function() {
// Uncheck all checkboxes and hide check marks
$('.product-checkbox').prop('checked', false);
$('.productset').removeClass('selected');
$('.check-product i').hide();
window.selectedProducts = [];
updateToolbar();
});
// Add selected products to cart
$('#add-selected-to-cart').on('click', function() {
if (window.selectedProducts.length > 0) {
console.log('Adding products to cart:', window.selectedProducts);
// Create a form to submit selected products
const form = $('<form>', {
method: 'post',
action: 'index.php'
});
// Add each product ID as a hidden input
window.selectedProducts.forEach(function(productId) {
form.append(
$('<input>').attr({
type: 'hidden',
name: 'product_ids[]',
value: productId
})
);
});
// Log form contents before submission
console.log('Form contents:', form.serialize());
// Add the form to the body and submit it
$('body').append(form);
form.submit();
}
});
}
/**
* Update the toolbar state based on selected products
*/
function updateToolbar() {
if (window.selectedProducts.length > 0) {
$('.selected-count').text(window.selectedProducts.length + ' item' + (window.selectedProducts.length > 1 ? 's' : '') + ' selected');
window.multiSelectToolbar.addClass('active');
} else {
window.multiSelectToolbar.removeClass('active');
}
}
/**
* Setup live search functionality
*/
function setupLiveSearch() {
// Handle both search inputs - top nav and product header search
const searchInputs = $('input[name="search"]');
// Store the original URL for reference
const originalUrl = window.location.href.split('?')[0];
const urlParams = new URLSearchParams(window.location.search);
// Clear search buttons functionality
$('.product-search-form a, .search-addon a').on('click', function(e) {
e.preventDefault();
urlParams.delete('search');
// Build the new URL
let newUrl = originalUrl;
const paramString = urlParams.toString();
if (paramString) {
newUrl += '?' + paramString;
}
// Navigate to the new URL
window.location.href = newUrl;
});
// Custom form submission to prevent loader
$('.product-search-form form, .top-nav-search form').on('submit', function(e) {
e.preventDefault(); // Prevent the default form submission
// Get the search query
const searchQuery = $(this).find('input[name="search"]').val().trim();
// Get any type filter
const typeParam = $(this).find('input[name="type"]').val();
// Build the URL
let newUrl = originalUrl;
if (searchQuery || typeParam) {
newUrl += '?';
if (searchQuery) {
newUrl += 'search=' + encodeURIComponent(searchQuery);
if (typeParam) {
newUrl += '&';
}
}
if (typeParam) {
newUrl += 'type=' + encodeURIComponent(typeParam);
}
}
// Use AJAX to fetch the page content
$.ajax({
url: newUrl,
type: 'GET',
beforeSend: function() {
// Add a simple loading indicator to the product area
$('.tab_content').addClass('loading');
$('.tab_content > .row').css('opacity', '0.5');
},
success: function(response) {
// Extract and replace just the product content
const $response = $(response);
const newProductContent = $response.find('.tab_content').html();
// Update the DOM with new content
$('.tab_content').html(newProductContent);
// Update browser URL without reloading
history.pushState({}, '', newUrl);
// Update search info area if it exists
const searchInfoContent = $response.find('.search-results-info').html();
if (searchInfoContent) {
if ($('.search-results-info').length) {
$('.search-results-info').html(searchInfoContent);
} else {
$('<div class="search-results-info mb-3"></div>')
.html(searchInfoContent)
.insertAfter('.page-header');
}
$('.search-results-info').show();
} else {
$('.search-results-info').hide();
}
// Update the other search input with the same value
searchInputs.val(searchQuery);
// Reset the loading state
$('.tab_content').removeClass('loading');
$('.tab_content > .row').css('opacity', '1');
// Reinitialize product selection for newly loaded products
setupProductSelection();
},
error: function() {
// If something goes wrong, just do a normal page load
window.location.href = newUrl;
}
});
});
}
/**
* Setup AJAX-based category navigation
*/
function setupCategoryNavigation() {
// Original URL for reference
const originalUrl = window.location.href.split('?')[0];
// Add click event handlers to all category links
$('.tabs li a.category-tab').on('click', function(e) {
e.preventDefault();
// Get category type from URL
const href = $(this).attr('href');
const url = new URL(href, window.location.origin);
const typeParam = url.searchParams.get('type');
// Get current search query if any
const currentUrl = new URL(window.location.href);
const searchQuery = currentUrl.searchParams.get('search');
// Build the target URL
let targetUrl = originalUrl;
const params = new URLSearchParams();
// Add type parameter if set
if (typeParam) {
params.set('type', typeParam);
}
// Preserve search query if exists
if (searchQuery) {
params.set('search', searchQuery);
}
// Append parameters to URL if any
const paramString = params.toString();
if (paramString) {
targetUrl += '?' + paramString;
}
// Highlight the active category tab
$('.tabs li').removeClass('active');
$(this).closest('li').addClass('active');
// Use AJAX to fetch the category products
$.ajax({
url: targetUrl,
type: 'GET',
beforeSend: function() {
// Add loading indicator to product area
$('.tab_content').addClass('loading');
$('.tab_content > .row').css('opacity', '0.5');
},
success: function(response) {
// Extract and replace just the product content
const $response = $(response);
const newProductContent = $response.find('.tab_content').html();
// Update the DOM with new content
$('.tab_content').html(newProductContent);
// Update browser URL without reloading
history.pushState({}, '', targetUrl);
// Reset the loading state
$('.tab_content').removeClass('loading');
$('.tab_content > .row').css('opacity', '1');
// Reinitialize product selection for newly loaded products
setupProductSelection();
},
error: function() {
// If something goes wrong, just do a normal page load
window.location.href = targetUrl;
}
});
});
}
/**
* Setup cash payment functionality
*/
function setupCashPayment() {
const cashInput = $('#cash-amount');
const changeDisplay = $('#change-amount');
const changeContainer = $('#change-container');
const hiddenCashAmount = $('#hidden-cash-amount');
const hiddenChangeAmount = $('#hidden-change-amount');
const totalAmount = parseFloat($('.total-value h6').text().replace(/[^\d]/g, ''));
// Format cash input with thousand separators
cashInput.on('input', function() {
// Remove non-numeric characters
let value = $(this).val().replace(/[^\d]/g, '');
// Convert to number and format with thousand separator
if (value !== '') {
const numericValue = parseInt(value);
// Calculate change
const change = numericValue - totalAmount;
// Update hidden fields for form submission - store raw numeric values
hiddenCashAmount.val(numericValue);
hiddenChangeAmount.val(Math.max(0, change));
// Format display value
$(this).val(formatNumber(numericValue));
// Show change if payment is sufficient
if (change >= 0) {
changeDisplay.text('Rp. ' + formatNumber(change));
changeContainer.show();
} else {
changeContainer.hide();
}
} else {
$(this).val('');
changeContainer.hide();
}
});
// Quick cash buttons
$('.quick-cash').on('click', function() {
const value = $(this).data('value');
cashInput.val(formatNumber(value));
// Calculate change
const change = value - totalAmount;
// Update hidden fields for form submission
hiddenCashAmount.val(value);
hiddenChangeAmount.val(Math.max(0, change));
// Show change
if (change >= 0) {
changeDisplay.text('Rp. ' + formatNumber(change));
changeContainer.show();
} else {
changeContainer.hide();
}
});
// Form submission check
$('#checkout-form').on('submit', function(e) {
const cashValue = parseFloat(hiddenCashAmount.val());
// Check if cash amount is sufficient
if (cashValue < totalAmount) {
e.preventDefault();
alert('Cash amount is not sufficient!');
return false;
}
return true;
});
// Trigger input event to initialize on page load
cashInput.trigger('input');
}
/**
* Format number with thousand separator
*/
function formatNumber(number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
}