797 lines
25 KiB
JavaScript
797 lines
25 KiB
JavaScript
// Sparkle effect on mouse move
|
|
document.addEventListener('mousemove', function (e) {
|
|
const emojis = ['✨', '💖', '🌟', '💅', '🦄', '🎉', '🌈'];
|
|
const sparkle = document.createElement('div');
|
|
sparkle.className = 'emoji-footprint';
|
|
sparkle.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
|
sparkle.style.left = e.pageX + 'px';
|
|
sparkle.style.top = e.pageY + 'px';
|
|
document.body.appendChild(sparkle);
|
|
|
|
setTimeout(() => {
|
|
sparkle.remove();
|
|
}, 1000);
|
|
});
|
|
|
|
// Dashboard, Order Management, Inventory Management, Settings, and Drink Type functionality
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Stock update form handling
|
|
initStockUpdateForms();
|
|
|
|
// Edit button handling
|
|
initEditButtons();
|
|
|
|
// Order form handling
|
|
initOrderForms();
|
|
|
|
// Order status form handling
|
|
initOrderStatusForms();
|
|
|
|
// Inventory form handling
|
|
initInventoryForm();
|
|
|
|
// Settings form handling
|
|
initSettingsForm();
|
|
|
|
// Drink Type form handling
|
|
initDrinkTypeForm();
|
|
});
|
|
|
|
/**
|
|
* Initialize stock update forms with AJAX submission and validation
|
|
*/
|
|
function initStockUpdateForms() {
|
|
// Get all stock update forms
|
|
const stockForms = document.querySelectorAll('.stock-update-form');
|
|
|
|
// Add event listener to each form
|
|
stockForms.forEach(form => {
|
|
// Add validation to quantity input
|
|
const quantityInput = form.querySelector('input[name="quantity"]');
|
|
if (quantityInput) {
|
|
quantityInput.addEventListener('input', function() {
|
|
validateQuantityInput(this);
|
|
});
|
|
}
|
|
|
|
// Add submit handler
|
|
form.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
// Validate form before submission
|
|
if (!validateStockForm(form)) {
|
|
return;
|
|
}
|
|
|
|
// Get form data
|
|
const formData = new FormData(form);
|
|
|
|
// Show loading state
|
|
const submitButton = form.querySelector('button[type="submit"]');
|
|
const originalText = submitButton.textContent;
|
|
submitButton.textContent = 'Updating...';
|
|
submitButton.disabled = true;
|
|
|
|
// Send AJAX request
|
|
fetch(form.action, {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
// Reset button state
|
|
submitButton.textContent = originalText;
|
|
submitButton.disabled = false;
|
|
|
|
if (data.success) {
|
|
// Show success message
|
|
showAlert(form.parentNode, 'success', 'Stock updated successfully.');
|
|
} else {
|
|
// Show error message
|
|
showAlert(form.parentNode, 'danger', `Error updating stock: ${data.message}`);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
// Reset button state
|
|
submitButton.textContent = originalText;
|
|
submitButton.disabled = false;
|
|
|
|
// Show error message
|
|
showAlert(form.parentNode, 'danger', `Error: ${error.message}`);
|
|
console.error('Error:', error);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize edit buttons
|
|
*/
|
|
function initEditButtons() {
|
|
const editButtons = document.querySelectorAll('.btn-edit-drink-type');
|
|
|
|
editButtons.forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
const drinkTypeId = this.dataset.drinkTypeId;
|
|
window.location.href = `/drink-types/edit/${drinkTypeId}`;
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Validate a stock update form
|
|
* @param {HTMLFormElement} form - The form to validate
|
|
* @returns {boolean} - Whether the form is valid
|
|
*/
|
|
function validateStockForm(form) {
|
|
const quantityInput = form.querySelector('input[name="quantity"]');
|
|
return validateQuantityInput(quantityInput);
|
|
}
|
|
|
|
/**
|
|
* Validate a quantity input
|
|
* @param {HTMLInputElement} input - The input to validate
|
|
* @returns {boolean} - Whether the input is valid
|
|
*/
|
|
function validateQuantityInput(input) {
|
|
const value = parseInt(input.value);
|
|
|
|
// Check if value is a number
|
|
if (isNaN(value)) {
|
|
input.classList.add('is-invalid');
|
|
showInputError(input, 'Please enter a valid number');
|
|
return false;
|
|
}
|
|
|
|
// Check if value is non-negative
|
|
if (value < 0) {
|
|
input.classList.add('is-invalid');
|
|
showInputError(input, 'Quantity cannot be negative');
|
|
return false;
|
|
}
|
|
|
|
// Input is valid
|
|
input.classList.remove('is-invalid');
|
|
input.classList.add('is-valid');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Show an error message for an input
|
|
* @param {HTMLInputElement} input - The input with the error
|
|
* @param {string} message - The error message
|
|
*/
|
|
function showInputError(input, message) {
|
|
// Remove any existing error message
|
|
const existingError = input.parentNode.querySelector('.invalid-feedback');
|
|
if (existingError) {
|
|
existingError.remove();
|
|
}
|
|
|
|
// Create and add new error message
|
|
const errorDiv = document.createElement('div');
|
|
errorDiv.className = 'invalid-feedback';
|
|
errorDiv.textContent = message;
|
|
input.parentNode.appendChild(errorDiv);
|
|
}
|
|
|
|
/**
|
|
* Show an alert message
|
|
* @param {HTMLElement} container - The container to add the alert to
|
|
* @param {string} type - The type of alert (success, danger, warning, info)
|
|
* @param {string} message - The alert message
|
|
*/
|
|
function showAlert(container, type, message) {
|
|
// Remove any existing alerts
|
|
const existingAlerts = container.querySelectorAll('.alert');
|
|
existingAlerts.forEach(alert => alert.remove());
|
|
|
|
// Create and add new alert
|
|
const alert = document.createElement('div');
|
|
alert.className = `alert alert-${type} alert-dismissible fade show mt-3`;
|
|
alert.innerHTML = `
|
|
${message}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
`;
|
|
container.appendChild(alert);
|
|
|
|
// Remove alert after 3 seconds
|
|
setTimeout(() => {
|
|
alert.remove();
|
|
}, 3000);
|
|
}
|
|
|
|
/**
|
|
* Initialize order forms with validation and dynamic item handling
|
|
*/
|
|
function initOrderForms() {
|
|
const orderForm = document.getElementById('orderForm');
|
|
if (!orderForm) return;
|
|
|
|
// Validate all quantity inputs
|
|
const quantityInputs = orderForm.querySelectorAll('input[type="number"]');
|
|
quantityInputs.forEach(input => {
|
|
input.addEventListener('input', function() {
|
|
validateQuantityInput(this);
|
|
});
|
|
});
|
|
|
|
// Add form submission handler
|
|
orderForm.addEventListener('submit', function(e) {
|
|
// Validate all inputs before submission
|
|
let isValid = true;
|
|
quantityInputs.forEach(input => {
|
|
if (!validateQuantityInput(input)) {
|
|
isValid = false;
|
|
}
|
|
});
|
|
|
|
if (!isValid) {
|
|
e.preventDefault();
|
|
showAlert(orderForm, 'danger', 'Please correct the errors in the form before submitting.');
|
|
}
|
|
});
|
|
|
|
// Add "Add Item" button functionality if it exists
|
|
const addItemButton = document.getElementById('addOrderItem');
|
|
if (addItemButton) {
|
|
addItemButton.addEventListener('click', function() {
|
|
addOrderItem();
|
|
});
|
|
}
|
|
|
|
// Add "Remove Item" button functionality
|
|
const removeButtons = orderForm.querySelectorAll('.remove-order-item');
|
|
removeButtons.forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
removeOrderItem(this);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Add a new order item row to the order form
|
|
*/
|
|
function addOrderItem() {
|
|
const orderItemsTable = document.querySelector('#orderForm table tbody');
|
|
const drinkTypeSelect = document.getElementById('drinkTypeSelect');
|
|
|
|
if (!orderItemsTable || !drinkTypeSelect) return;
|
|
|
|
// Get the selected drink type
|
|
const selectedOption = drinkTypeSelect.options[drinkTypeSelect.selectedIndex];
|
|
const drinkTypeId = selectedOption.value;
|
|
const drinkTypeName = selectedOption.text;
|
|
|
|
// Check if this drink type is already in the table
|
|
const existingRow = orderItemsTable.querySelector(`input[value="${drinkTypeId}"]`);
|
|
if (existingRow) {
|
|
showAlert(orderItemsTable.parentNode, 'warning', `${drinkTypeName} is already in the order.`);
|
|
return;
|
|
}
|
|
|
|
// Create a new row
|
|
const newRow = document.createElement('tr');
|
|
const rowCount = orderItemsTable.querySelectorAll('tr').length;
|
|
|
|
newRow.innerHTML = `
|
|
<td>${drinkTypeName}</td>
|
|
<td>
|
|
<input type="hidden" name="items[${rowCount}][drinkTypeId]" value="${drinkTypeId}">
|
|
<input type="number" name="items[${rowCount}][quantity]"
|
|
class="form-control form-control-sm order-quantity"
|
|
value="1" min="0">
|
|
</td>
|
|
<td>
|
|
<button type="button" class="btn btn-sm btn-danger remove-order-item">Remove</button>
|
|
</td>
|
|
`;
|
|
|
|
// Add event listeners to the new row
|
|
const quantityInput = newRow.querySelector('input[type="number"]');
|
|
quantityInput.addEventListener('input', function() {
|
|
validateQuantityInput(this);
|
|
});
|
|
|
|
const removeButton = newRow.querySelector('.remove-order-item');
|
|
removeButton.addEventListener('click', function() {
|
|
removeOrderItem(this);
|
|
});
|
|
|
|
// Add the row to the table
|
|
orderItemsTable.appendChild(newRow);
|
|
}
|
|
|
|
/**
|
|
* Remove an order item row from the order form
|
|
* @param {HTMLElement} button - The remove button that was clicked
|
|
*/
|
|
function removeOrderItem(button) {
|
|
const row = button.closest('tr');
|
|
if (row) {
|
|
row.remove();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize order status forms with AJAX submission
|
|
*/
|
|
function initOrderStatusForms() {
|
|
const statusForm = document.querySelector('form[action^="/orders/update-status/"]');
|
|
if (!statusForm) return;
|
|
|
|
statusForm.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
// Get form data
|
|
const formData = new FormData(statusForm);
|
|
|
|
// Show loading state
|
|
const submitButton = statusForm.querySelector('button[type="submit"]');
|
|
const originalText = submitButton.textContent;
|
|
submitButton.textContent = 'Updating...';
|
|
submitButton.disabled = true;
|
|
|
|
// Send AJAX request
|
|
fetch(statusForm.action, {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
// Reset button state
|
|
submitButton.textContent = originalText;
|
|
submitButton.disabled = false;
|
|
|
|
if (data.success) {
|
|
// Show success message
|
|
showAlert(statusForm.parentNode, 'success', 'Order status updated successfully.');
|
|
|
|
// Update the status badge
|
|
const statusBadge = document.querySelector('.badge');
|
|
if (statusBadge) {
|
|
// Remove old status classes
|
|
statusBadge.classList.remove('bg-primary', 'bg-warning', 'bg-info', 'bg-success');
|
|
|
|
// Add new status class
|
|
const newStatus = formData.get('status');
|
|
if (newStatus === 'new') {
|
|
statusBadge.classList.add('bg-primary');
|
|
} else if (newStatus === 'in_work') {
|
|
statusBadge.classList.add('bg-warning');
|
|
} else if (newStatus === 'ordered') {
|
|
statusBadge.classList.add('bg-info');
|
|
} else if (newStatus === 'fulfilled') {
|
|
statusBadge.classList.add('bg-success');
|
|
}
|
|
|
|
// Update the text
|
|
statusBadge.textContent = newStatus.charAt(0).toUpperCase() + newStatus.slice(1);
|
|
}
|
|
} else {
|
|
// Show error message
|
|
showAlert(statusForm.parentNode, 'danger', `Error updating status: ${data.message}`);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
// Reset button state
|
|
submitButton.textContent = originalText;
|
|
submitButton.disabled = false;
|
|
|
|
// Show error message
|
|
showAlert(statusForm.parentNode, 'danger', `Error: ${error.message}`);
|
|
console.error('Error:', error);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize inventory form with validation, highlighting for changed values, and AJAX submission
|
|
*/
|
|
function initInventoryForm() {
|
|
const inventoryForm = document.getElementById('inventoryForm');
|
|
if (!inventoryForm) return;
|
|
|
|
// Get all quantity inputs
|
|
const quantityInputs = inventoryForm.querySelectorAll('.inventory-quantity');
|
|
|
|
// Add event listener to each input for validation and highlighting
|
|
quantityInputs.forEach(input => {
|
|
// Store original value for comparison
|
|
const originalValue = parseInt(input.dataset.originalValue);
|
|
|
|
// Add input event listener for validation
|
|
input.addEventListener('input', function() {
|
|
// Validate input
|
|
validateQuantityInput(this);
|
|
|
|
// Highlight changed values
|
|
const currentValue = parseInt(this.value);
|
|
if (currentValue !== originalValue) {
|
|
this.classList.add('bg-warning', 'text-dark');
|
|
} else {
|
|
this.classList.remove('bg-warning', 'text-dark');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Add submit handler
|
|
inventoryForm.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
// Validate all inputs before submission
|
|
let isValid = true;
|
|
quantityInputs.forEach(input => {
|
|
if (!validateQuantityInput(input)) {
|
|
isValid = false;
|
|
}
|
|
});
|
|
|
|
if (!isValid) {
|
|
showAlert(inventoryForm, 'danger', 'Please correct the errors in the form before submitting.');
|
|
return;
|
|
}
|
|
|
|
// Check if any values have changed
|
|
let hasChanges = false;
|
|
quantityInputs.forEach(input => {
|
|
const originalValue = parseInt(input.dataset.originalValue);
|
|
const currentValue = parseInt(input.value);
|
|
if (currentValue !== originalValue) {
|
|
hasChanges = true;
|
|
}
|
|
});
|
|
|
|
if (!hasChanges) {
|
|
showAlert(inventoryForm, 'warning', 'No changes detected. Nothing to update.');
|
|
return;
|
|
}
|
|
|
|
// Get form data
|
|
const formData = new FormData(inventoryForm);
|
|
|
|
// Add X-Requested-With header to indicate AJAX request
|
|
const headers = new Headers({
|
|
'X-Requested-With': 'XMLHttpRequest'
|
|
});
|
|
|
|
// Show loading state
|
|
const submitButton = inventoryForm.querySelector('button[type="submit"]');
|
|
const originalText = submitButton.textContent;
|
|
submitButton.textContent = 'Updating...';
|
|
submitButton.disabled = true;
|
|
|
|
// Send AJAX request
|
|
fetch(inventoryForm.action, {
|
|
method: 'POST',
|
|
headers: headers,
|
|
body: formData
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
// Reset button state
|
|
submitButton.textContent = originalText;
|
|
submitButton.disabled = false;
|
|
|
|
if (data.success) {
|
|
// Show success message
|
|
showAlert(inventoryForm, 'success', 'Inventory updated successfully.');
|
|
|
|
// Update original values and remove highlighting
|
|
quantityInputs.forEach(input => {
|
|
const drinkTypeId = input.previousElementSibling.value;
|
|
const updatedItem = data.updatedItems.find(item => item.drinkTypeId == drinkTypeId);
|
|
|
|
if (updatedItem) {
|
|
input.dataset.originalValue = updatedItem.newQuantity;
|
|
input.classList.remove('bg-warning', 'text-dark');
|
|
}
|
|
});
|
|
|
|
// Show update results
|
|
const updateResults = document.getElementById('updateResults');
|
|
const updateResultsContent = document.getElementById('updateResultsContent');
|
|
|
|
if (updateResults && updateResultsContent) {
|
|
updateResults.classList.remove('d-none');
|
|
|
|
let resultsHtml = '<h6>The following items were updated:</h6><ul>';
|
|
data.updatedItems.forEach(item => {
|
|
resultsHtml += `<li>${item.name}: ${item.oldQuantity} → ${item.newQuantity}</li>`;
|
|
});
|
|
resultsHtml += '</ul>';
|
|
|
|
updateResultsContent.innerHTML = resultsHtml;
|
|
}
|
|
} else {
|
|
// Show error message
|
|
let errorMessage = 'Error updating inventory.';
|
|
if (data.errors && data.errors.length > 0) {
|
|
errorMessage += ' ' + data.errors.join(' ');
|
|
}
|
|
showAlert(inventoryForm, 'danger', errorMessage);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
// Reset button state
|
|
submitButton.textContent = originalText;
|
|
submitButton.disabled = false;
|
|
|
|
// Show error message
|
|
showAlert(inventoryForm, 'danger', `Error: ${error.message}`);
|
|
console.error('Error:', error);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize settings form with validation and AJAX submission
|
|
*/
|
|
function initSettingsForm() {
|
|
const settingsForm = document.getElementById('settings-form');
|
|
if (!settingsForm) return;
|
|
|
|
// Get all inputs
|
|
const textInputs = settingsForm.querySelectorAll('input[type="text"]');
|
|
const numberInputs = settingsForm.querySelectorAll('input[type="number"]');
|
|
|
|
// Add event listeners for validation
|
|
textInputs.forEach(input => {
|
|
input.addEventListener('input', function() {
|
|
validateSettingTextInput(this);
|
|
});
|
|
});
|
|
|
|
numberInputs.forEach(input => {
|
|
input.addEventListener('input', function() {
|
|
validateSettingNumberInput(this);
|
|
});
|
|
});
|
|
|
|
// Add submit handler
|
|
settingsForm.addEventListener('submit', function(e) {
|
|
// Validate all inputs before submission
|
|
let isValid = true;
|
|
|
|
textInputs.forEach(input => {
|
|
if (!validateSettingTextInput(input)) {
|
|
isValid = false;
|
|
}
|
|
});
|
|
|
|
numberInputs.forEach(input => {
|
|
if (!validateSettingNumberInput(input)) {
|
|
isValid = false;
|
|
}
|
|
});
|
|
|
|
if (!isValid) {
|
|
e.preventDefault();
|
|
showAlert(settingsForm, 'danger', 'Please correct the errors in the form before submitting.');
|
|
}
|
|
});
|
|
|
|
// Reset to defaults button
|
|
const resetButton = document.getElementById('reset-defaults');
|
|
if (resetButton) {
|
|
resetButton.addEventListener('click', function() {
|
|
if (confirm('Are you sure you want to reset all settings to their default values?')) {
|
|
window.location.href = '/settings/reset';
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate a text input for settings
|
|
* @param {HTMLInputElement} input - The input to validate
|
|
* @returns {boolean} - Whether the input is valid
|
|
*/
|
|
function validateSettingTextInput(input) {
|
|
// Check if value is empty
|
|
if (input.value.trim() === '') {
|
|
input.classList.add('is-invalid');
|
|
showInputError(input, 'This field cannot be empty');
|
|
return false;
|
|
}
|
|
|
|
// Input is valid
|
|
input.classList.remove('is-invalid');
|
|
input.classList.add('is-valid');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Validate a number input for settings
|
|
* @param {HTMLInputElement} input - The input to validate
|
|
* @returns {boolean} - Whether the input is valid
|
|
*/
|
|
function validateSettingNumberInput(input) {
|
|
const value = parseInt(input.value);
|
|
|
|
// Check if value is a number
|
|
if (isNaN(value)) {
|
|
input.classList.add('is-invalid');
|
|
showInputError(input, 'Please enter a valid number');
|
|
return false;
|
|
}
|
|
|
|
// Check if value is positive
|
|
if (value < 1) {
|
|
input.classList.add('is-invalid');
|
|
showInputError(input, 'Please enter a positive number');
|
|
return false;
|
|
}
|
|
|
|
// Input is valid
|
|
input.classList.remove('is-invalid');
|
|
input.classList.add('is-valid');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Initialize drink type form with validation and AJAX name uniqueness check
|
|
*/
|
|
function initDrinkTypeForm() {
|
|
const drinkTypeForm = document.getElementById('drink-type-form');
|
|
if (!drinkTypeForm) return;
|
|
|
|
// Get form inputs
|
|
const nameInput = drinkTypeForm.querySelector('input[name="name"]');
|
|
const descriptionInput = drinkTypeForm.querySelector('textarea[name="description"]');
|
|
const desiredStockInput = drinkTypeForm.querySelector('input[name="desired_stock"]');
|
|
|
|
// Store original name for edit mode
|
|
const originalName = nameInput ? nameInput.value : '';
|
|
|
|
// Add validation for name input
|
|
if (nameInput) {
|
|
nameInput.addEventListener('input', function() {
|
|
validateDrinkTypeName(this, originalName);
|
|
});
|
|
|
|
// Check name uniqueness on blur
|
|
nameInput.addEventListener('blur', function() {
|
|
checkDrinkTypeNameUniqueness(this, originalName);
|
|
});
|
|
}
|
|
|
|
// Add validation for desired stock input
|
|
if (desiredStockInput) {
|
|
desiredStockInput.addEventListener('input', function() {
|
|
validateDesiredStock(this);
|
|
});
|
|
}
|
|
|
|
// Add form submission handler
|
|
drinkTypeForm.addEventListener('submit', function(e) {
|
|
let isValid = true;
|
|
|
|
// Validate name
|
|
if (nameInput && !validateDrinkTypeName(nameInput, originalName)) {
|
|
isValid = false;
|
|
}
|
|
|
|
// Validate desired stock
|
|
if (desiredStockInput && !validateDesiredStock(desiredStockInput)) {
|
|
isValid = false;
|
|
}
|
|
|
|
if (!isValid) {
|
|
e.preventDefault();
|
|
showAlert(drinkTypeForm, 'danger', 'Please correct the errors in the form before submitting.');
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Validate a drink type name
|
|
* @param {HTMLInputElement} input - The input to validate
|
|
* @param {string} originalName - The original name (for edit mode)
|
|
* @returns {boolean} - Whether the input is valid
|
|
*/
|
|
function validateDrinkTypeName(input, originalName) {
|
|
const value = input.value.trim();
|
|
|
|
// Check if value is empty
|
|
if (value === '') {
|
|
input.classList.add('is-invalid');
|
|
showInputError(input, 'Name is required');
|
|
return false;
|
|
}
|
|
|
|
// Check if value is too long
|
|
if (value.length > 255) {
|
|
input.classList.add('is-invalid');
|
|
showInputError(input, 'Name cannot be longer than 255 characters');
|
|
return false;
|
|
}
|
|
|
|
// Input is valid
|
|
input.classList.remove('is-invalid');
|
|
input.classList.add('is-valid');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check if a drink type name is unique
|
|
* @param {HTMLInputElement} input - The input to check
|
|
* @param {string} originalName - The original name (for edit mode)
|
|
*/
|
|
function checkDrinkTypeNameUniqueness(input, originalName) {
|
|
const value = input.value.trim();
|
|
|
|
// Skip check if name hasn't changed or is empty
|
|
if (value === '' || value === originalName) {
|
|
return;
|
|
}
|
|
|
|
// Show loading state
|
|
input.classList.add('is-loading');
|
|
|
|
// Check if name already exists
|
|
fetch(`/api/drink-types/check-name?name=${encodeURIComponent(value)}`)
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
// Remove loading state
|
|
input.classList.remove('is-loading');
|
|
|
|
if (data.exists) {
|
|
input.classList.add('is-invalid');
|
|
showInputError(input, 'A drink type with this name already exists');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
// Remove loading state
|
|
input.classList.remove('is-loading');
|
|
console.error('Error checking name uniqueness:', error);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Validate a desired stock input
|
|
* @param {HTMLInputElement} input - The input to validate
|
|
* @returns {boolean} - Whether the input is valid
|
|
*/
|
|
function validateDesiredStock(input) {
|
|
const value = parseInt(input.value);
|
|
|
|
// Check if value is a number
|
|
if (isNaN(value)) {
|
|
input.classList.add('is-invalid');
|
|
showInputError(input, 'Desired stock must be a number');
|
|
return false;
|
|
}
|
|
|
|
// Check if value is non-negative
|
|
if (value < 0) {
|
|
input.classList.add('is-invalid');
|
|
showInputError(input, 'Desired stock cannot be negative');
|
|
return false;
|
|
}
|
|
|
|
// Input is valid
|
|
input.classList.remove('is-invalid');
|
|
input.classList.add('is-valid');
|
|
return true;
|
|
}
|