710 lines
24 KiB
JavaScript
710 lines
24 KiB
JavaScript
// Settings page functionality
|
|
|
|
// ========== Legacy functions (kept for backward compatibility) ==========
|
|
function testPrinter() {
|
|
const resultEl = document.getElementById('printerTestResult');
|
|
const selectedHidden = document.getElementById('selectedPrintersJson');
|
|
resultEl.textContent = 'Testing...';
|
|
resultEl.style.color = '#666';
|
|
|
|
const body = JSON.stringify({
|
|
selectedPrintersJson: selectedHidden ? selectedHidden.value : '[]'
|
|
});
|
|
|
|
fetch('/settings/test-printer', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (!data.error) {
|
|
resultEl.textContent = '✓ ' + data.message;
|
|
resultEl.style.color = '#28a745';
|
|
} else {
|
|
resultEl.textContent = '✗ ' + (data.message || 'Test failed');
|
|
resultEl.style.color = '#dc3545';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Test print error:', error);
|
|
resultEl.textContent = '✗ Network error';
|
|
resultEl.style.color = '#dc3545';
|
|
});
|
|
}
|
|
|
|
async function uploadLogo() {
|
|
const fileInput = document.getElementById('logoUpload');
|
|
const file = fileInput.files[0];
|
|
|
|
if (!file) {
|
|
alert('Please select a file first');
|
|
return;
|
|
}
|
|
|
|
const validTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'];
|
|
if (!validTypes.includes(file.type)) {
|
|
alert('Please select a valid image file (PNG, JPG, or GIF)');
|
|
return;
|
|
}
|
|
|
|
if (file.size > 5 * 1024 * 1024) {
|
|
alert('File size must be less than 5MB');
|
|
return;
|
|
}
|
|
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
try {
|
|
const response = await fetch('/settings/upload-logo', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (!data.error) {
|
|
alert('Logo uploaded successfully!');
|
|
location.reload();
|
|
} else {
|
|
alert('Upload failed: ' + (data.message || 'Unknown error'));
|
|
}
|
|
} catch (error) {
|
|
console.error('Logo upload error:', error);
|
|
alert('Upload failed: Network error');
|
|
}
|
|
}
|
|
|
|
// ========== New Printer Management Functions ==========
|
|
|
|
let currentPrinterId = null;
|
|
|
|
// Load and display printers
|
|
async function loadPrinters() {
|
|
const container = document.getElementById('printer-cards-container');
|
|
if (!container) return;
|
|
|
|
try {
|
|
const response = await fetch('/api/printers/list');
|
|
const data = await response.json();
|
|
|
|
if (data.error || !data.printers || data.printers.length === 0) {
|
|
container.innerHTML = `
|
|
<div class="no-printers">
|
|
<p>No printers configured yet.</p>
|
|
<p>Click "Add Printer" to configure your first printer.</p>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
// Render printer cards
|
|
const cardsHTML = data.printers.map(printer => createPrinterCard(printer)).join('');
|
|
container.innerHTML = cardsHTML;
|
|
} catch (error) {
|
|
console.error('Failed to load printers:', error);
|
|
container.innerHTML = `<div class="alert alert-error">Failed to load printers: ${error.message}</div>`;
|
|
}
|
|
}
|
|
|
|
// Create HTML for a printer card
|
|
function createPrinterCard(printer) {
|
|
const defaultBadge = printer.is_default ? '<span class="printer-badge badge-default">DEFAULT</span>' : '';
|
|
const enabledBadge = printer.is_enabled
|
|
? '<span class="printer-badge badge-enabled">ENABLED</span>'
|
|
: '<span class="printer-badge badge-disabled">DISABLED</span>';
|
|
|
|
const typeLabel = {
|
|
'network': 'Network',
|
|
'com': 'Serial/COM',
|
|
'usb': 'USB',
|
|
'system': 'System Printer'
|
|
}[printer.type] || printer.type;
|
|
|
|
return `
|
|
<div class="printer-card ${!printer.is_enabled ? 'disabled' : ''}">
|
|
<div class="printer-card-header">
|
|
<div>
|
|
<h4>${escapeHtml(printer.name)}</h4>
|
|
<div class="printer-badges">
|
|
${defaultBadge}
|
|
${enabledBadge}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="printer-card-body">
|
|
<div class="printer-info-row">
|
|
<span class="printer-info-label">Connection:</span>
|
|
<span class="printer-info-value">${typeLabel}: ${escapeHtml(printer.interface)}</span>
|
|
</div>
|
|
<div class="printer-info-row">
|
|
<span class="printer-info-label">Paper:</span>
|
|
<span class="printer-info-value">${printer.paper_format} (${printer.paper_width} chars) | ${printer.printer_type}</span>
|
|
</div>
|
|
</div>
|
|
<div class="printer-card-actions">
|
|
<button type="button" class="btn btn-secondary btn-sm" onclick="editPrinter(${printer.id})">Edit</button>
|
|
<button type="button" class="btn btn-secondary btn-sm" onclick="testPrinterById(${printer.id})">Test</button>
|
|
${!printer.is_default ? `<button type="button" class="btn btn-secondary btn-sm" onclick="setDefaultPrinter(${printer.id})">Set Default</button>` : ''}
|
|
<button type="button" class="btn btn-secondary btn-sm" onclick="togglePrinterEnabled(${printer.id})">${printer.is_enabled ? 'Disable' : 'Enable'}</button>
|
|
${!printer.is_default ? `<button type="button" class="btn btn-danger btn-sm" onclick="deletePrinter(${printer.id})">Delete</button>` : ''}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// Escape HTML to prevent XSS
|
|
function escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
// Open add printer modal
|
|
function openAddPrinterModal() {
|
|
currentPrinterId = null;
|
|
document.getElementById('printerModalTitle').textContent = 'Add Printer';
|
|
document.getElementById('printerConfigForm').reset();
|
|
document.getElementById('printer_id').value = '';
|
|
|
|
// Set defaults
|
|
document.getElementById('paper_width').value = 48;
|
|
document.getElementById('paper_format').value = '80mm';
|
|
document.getElementById('printer_type_model').value = 'epson';
|
|
document.getElementById('font_size').value = 'normal';
|
|
document.getElementById('line_style').value = 'single';
|
|
document.getElementById('qr_code_size').value = 3;
|
|
document.getElementById('qr_code_correction').value = 'M';
|
|
document.getElementById('qr_code_content_template').value = 'ORDER-{id}';
|
|
document.getElementById('header_text').value = '';
|
|
document.getElementById('footer_text').value = '';
|
|
document.getElementById('business_contact_size').value = 'normal';
|
|
|
|
// Pre-fill Business Information from Receipt Template tab
|
|
try {
|
|
const tplBusinessName = document.getElementById('businessName');
|
|
const tplBusinessAddress = document.getElementById('businessAddress');
|
|
const tplBusinessPhone = document.getElementById('businessPhone');
|
|
const tplBusinessWebsite = document.getElementById('businessWebsite');
|
|
const tplBusinessEmail = document.getElementById('businessEmail');
|
|
const tplBusinessContactSize = document.getElementById('businessContactSize');
|
|
|
|
if (tplBusinessName) document.getElementById('business_name').value = tplBusinessName.value || '';
|
|
if (tplBusinessAddress) document.getElementById('business_address').value = tplBusinessAddress.value || '';
|
|
if (tplBusinessPhone) document.getElementById('business_phone').value = tplBusinessPhone.value || '';
|
|
if (tplBusinessWebsite) document.getElementById('business_website').value = tplBusinessWebsite.value || '';
|
|
if (tplBusinessEmail) document.getElementById('business_email').value = tplBusinessEmail.value || '';
|
|
if (tplBusinessContactSize) document.getElementById('business_contact_size').value = tplBusinessContactSize.value || 'normal';
|
|
} catch (_) {}
|
|
|
|
// Set checkboxes
|
|
document.getElementById('show_customer_info').checked = true;
|
|
document.getElementById('show_order_items').checked = true;
|
|
document.getElementById('show_prices').checked = true;
|
|
document.getElementById('show_timestamps').checked = true;
|
|
document.getElementById('qr_code_enabled').checked = true;
|
|
document.getElementById('is_enabled').checked = true;
|
|
document.getElementById('is_default').checked = false;
|
|
|
|
showModal('printerConfigModal');
|
|
switchPrinterModalTab('connection');
|
|
}
|
|
|
|
// Edit printer
|
|
async function editPrinter(id) {
|
|
try {
|
|
const response = await fetch(`/api/printers/${id}`);
|
|
const data = await response.json();
|
|
|
|
if (data.error) {
|
|
alert('Failed to load printer: ' + data.message);
|
|
return;
|
|
}
|
|
|
|
const printer = data.printer;
|
|
currentPrinterId = id;
|
|
|
|
document.getElementById('printerModalTitle').textContent = 'Edit Printer';
|
|
document.getElementById('printer_id').value = id;
|
|
|
|
// Fill form with printer data
|
|
document.getElementById('printer_name').value = printer.name || '';
|
|
document.getElementById('printer_type_select').value = printer.type || 'network';
|
|
document.getElementById('printer_interface').value = printer.interface || '';
|
|
document.getElementById('paper_format').value = printer.paper_format || '80mm';
|
|
document.getElementById('paper_width').value = printer.paper_width || 48;
|
|
document.getElementById('printer_type_model').value = printer.printer_type || 'epson';
|
|
document.getElementById('font_size').value = printer.font_size || 'normal';
|
|
document.getElementById('line_style').value = printer.line_style || 'single';
|
|
|
|
document.getElementById('header_text').value = printer.header_text || '';
|
|
document.getElementById('footer_text').value = printer.footer_text || '';
|
|
|
|
document.getElementById('business_name').value = printer.business_name || '';
|
|
document.getElementById('business_address').value = printer.business_address || '';
|
|
document.getElementById('business_phone').value = printer.business_phone || '';
|
|
document.getElementById('business_website').value = printer.business_website || '';
|
|
document.getElementById('business_email').value = printer.business_email || '';
|
|
document.getElementById('business_contact_size').value = printer.business_contact_size || 'normal';
|
|
|
|
document.getElementById('logo_path').value = printer.logo_path || '';
|
|
document.getElementById('logo_max_width_dots').value = printer.logo_max_width_dots || '';
|
|
|
|
if (printer.logo_path) {
|
|
document.getElementById('logo_preview').innerHTML = `<small>Current logo: ${printer.logo_path}</small>`;
|
|
} else {
|
|
document.getElementById('logo_preview').innerHTML = '';
|
|
}
|
|
|
|
document.getElementById('qr_code_size').value = printer.qr_code_size || 3;
|
|
document.getElementById('qr_code_correction').value = printer.qr_code_correction || 'M';
|
|
document.getElementById('qr_code_content_template').value = printer.qr_code_content_template || 'ORDER-{id}';
|
|
|
|
document.getElementById('show_customer_info').checked = printer.show_customer_info !== false;
|
|
document.getElementById('show_order_items').checked = printer.show_order_items !== false;
|
|
document.getElementById('show_prices').checked = printer.show_prices !== false;
|
|
document.getElementById('show_timestamps').checked = printer.show_timestamps !== false;
|
|
document.getElementById('qr_code_enabled').checked = printer.qr_code_enabled !== false;
|
|
document.getElementById('is_default').checked = printer.is_default || false;
|
|
document.getElementById('is_enabled').checked = printer.is_enabled !== false;
|
|
|
|
showModal('printerConfigModal');
|
|
switchPrinterModalTab('connection');
|
|
} catch (error) {
|
|
console.error('Failed to load printer:', error);
|
|
alert('Failed to load printer: ' + error.message);
|
|
}
|
|
}
|
|
|
|
// Save printer configuration
|
|
async function savePrinterConfig() {
|
|
const form = document.getElementById('printerConfigForm');
|
|
|
|
if (!form.checkValidity()) {
|
|
form.reportValidity();
|
|
return;
|
|
}
|
|
|
|
const formData = new FormData(form);
|
|
const config = {};
|
|
|
|
for (const [key, value] of formData.entries()) {
|
|
if (key === 'id' && !value) continue; // Skip empty id
|
|
|
|
// Handle checkboxes
|
|
if (['show_customer_info', 'show_order_items', 'show_prices', 'show_timestamps', 'qr_code_enabled', 'is_default', 'is_enabled'].includes(key)) {
|
|
config[key] = document.getElementById(key).checked;
|
|
} else if (key === 'paper_width' || key === 'qr_code_size' || key === 'logo_max_width_dots') {
|
|
const val = parseInt(value, 10);
|
|
if (!isNaN(val) && val > 0) config[key] = val;
|
|
} else {
|
|
config[key] = value;
|
|
}
|
|
}
|
|
|
|
// Ensure checkbox fields are always present in payload (unchecked boxes are omitted from FormData by default)
|
|
['show_customer_info', 'show_order_items', 'show_prices', 'show_timestamps', 'qr_code_enabled', 'is_default', 'is_enabled'].forEach((key) => {
|
|
const el = document.getElementById(key);
|
|
if (el) {
|
|
config[key] = !!el.checked;
|
|
}
|
|
});
|
|
|
|
try {
|
|
const printerId = document.getElementById('printer_id').value;
|
|
const url = printerId ? `/api/printers/${printerId}` : '/api/printers/create';
|
|
const method = printerId ? 'PUT' : 'POST';
|
|
|
|
const response = await fetch(url, {
|
|
method: method,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(config)
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.error) {
|
|
alert('Failed to save printer: ' + data.message);
|
|
return;
|
|
}
|
|
|
|
alert(data.message || 'Printer saved successfully');
|
|
closePrinterModal();
|
|
loadPrinters();
|
|
} catch (error) {
|
|
console.error('Failed to save printer:', error);
|
|
alert('Failed to save printer: ' + error.message);
|
|
}
|
|
}
|
|
|
|
// Delete printer
|
|
async function deletePrinter(id) {
|
|
if (!confirm('Are you sure you want to delete this printer?')) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`/api/printers/${id}`, { method: 'DELETE' });
|
|
const data = await response.json();
|
|
|
|
if (data.error) {
|
|
alert('Failed to delete printer: ' + data.message);
|
|
return;
|
|
}
|
|
|
|
alert('Printer deleted successfully');
|
|
loadPrinters();
|
|
} catch (error) {
|
|
console.error('Failed to delete printer:', error);
|
|
alert('Failed to delete printer: ' + error.message);
|
|
}
|
|
}
|
|
|
|
// Test printer
|
|
async function testPrinterById(id) {
|
|
try {
|
|
const response = await fetch(`/api/printers/${id}/test`, { method: 'POST' });
|
|
const data = await response.json();
|
|
|
|
if (data.error) {
|
|
alert('Test failed: ' + data.message);
|
|
} else {
|
|
alert(data.message || 'Test print sent successfully');
|
|
}
|
|
} catch (error) {
|
|
console.error('Test print error:', error);
|
|
alert('Test failed: ' + error.message);
|
|
}
|
|
}
|
|
|
|
// Set default printer
|
|
async function setDefaultPrinter(id) {
|
|
try {
|
|
const response = await fetch(`/api/printers/${id}/set-default`, { method: 'POST' });
|
|
const data = await response.json();
|
|
|
|
if (data.error) {
|
|
alert('Failed to set default: ' + data.message);
|
|
} else {
|
|
loadPrinters();
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to set default:', error);
|
|
alert('Failed to set default: ' + error.message);
|
|
}
|
|
}
|
|
|
|
// Toggle printer enabled
|
|
async function togglePrinterEnabled(id) {
|
|
try {
|
|
const response = await fetch(`/api/printers/${id}/toggle-enabled`, { method: 'POST' });
|
|
const data = await response.json();
|
|
|
|
if (data.error) {
|
|
alert('Failed to toggle printer: ' + data.message);
|
|
} else {
|
|
loadPrinters();
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to toggle printer:', error);
|
|
alert('Failed to toggle printer: ' + error.message);
|
|
}
|
|
}
|
|
|
|
// Upload logo for specific printer
|
|
async function uploadLogoForPrinter() {
|
|
const fileInput = document.getElementById('logo_upload_modal');
|
|
const file = fileInput.files[0];
|
|
|
|
if (!file) {
|
|
alert('Please select a file first');
|
|
return;
|
|
}
|
|
|
|
const validTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'];
|
|
if (!validTypes.includes(file.type)) {
|
|
alert('Please select a valid image file (PNG, JPG, or GIF)');
|
|
return;
|
|
}
|
|
|
|
if (file.size > 5 * 1024 * 1024) {
|
|
alert('File size must be less than 5MB');
|
|
return;
|
|
}
|
|
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
|
|
// If editing existing printer, include printer_id
|
|
const printerId = document.getElementById('printer_id').value;
|
|
if (printerId) {
|
|
formData.append('printer_id', printerId);
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/settings/upload-logo', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (!data.error) {
|
|
alert('Logo uploaded successfully');
|
|
document.getElementById('logo_path').value = data.filepath;
|
|
document.getElementById('logo_preview').innerHTML = `<small>Logo uploaded: ${data.filepath}</small>`;
|
|
} else {
|
|
alert('Upload failed: ' + (data.message || 'Unknown error'));
|
|
}
|
|
} catch (error) {
|
|
console.error('Logo upload error:', error);
|
|
alert('Upload failed: Network error');
|
|
}
|
|
}
|
|
|
|
// Detect printers for modal
|
|
async function detectPrintersForModal() {
|
|
const listEl = document.getElementById('detected-printers-list');
|
|
listEl.innerHTML = '<p>Detecting printers...</p>';
|
|
|
|
try {
|
|
const response = await fetch('/api/printers/detect');
|
|
const data = await response.json();
|
|
|
|
if (data.error || !data.printers || data.printers.length === 0) {
|
|
listEl.innerHTML = '<p>No printers detected.</p>';
|
|
return;
|
|
}
|
|
|
|
const items = data.printers.map(p => {
|
|
const typeLabel = {
|
|
'system': 'System',
|
|
'com': 'COM'
|
|
}[p.type] || p.type;
|
|
|
|
return `
|
|
<div class="detected-printer-item">
|
|
<span><strong>${escapeHtml(p.name)}</strong> (${typeLabel})</span>
|
|
<button type="button" class="btn btn-secondary btn-sm" onclick="selectDetectedPrinter('${p.type}', '${escapeHtml(p.interface)}')">Use This</button>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
|
|
listEl.innerHTML = items;
|
|
} catch (error) {
|
|
console.error('Failed to detect printers:', error);
|
|
listEl.innerHTML = '<p>Failed to detect printers.</p>';
|
|
}
|
|
}
|
|
|
|
// Select a detected printer
|
|
function selectDetectedPrinter(type, interface) {
|
|
document.getElementById('printer_type_select').value = type;
|
|
document.getElementById('printer_interface').value = interface;
|
|
updateInterfaceHint();
|
|
}
|
|
|
|
// Update interface hint based on connection type
|
|
function updateInterfaceHint() {
|
|
const type = document.getElementById('printer_type_select').value;
|
|
const hintEl = document.getElementById('interface_hint');
|
|
|
|
const hints = {
|
|
'network': 'Enter IP:Port for network printers (e.g., 192.168.1.100:9100)',
|
|
'com': 'Enter COM port (e.g., COM1, COM3)',
|
|
'usb': 'Enter USB device path (e.g., /dev/usb/lp0)',
|
|
'system': 'Enter the exact printer name from Windows'
|
|
};
|
|
|
|
hintEl.textContent = hints[type] || 'Enter connection address';
|
|
}
|
|
|
|
// Auto-update paper width when format changes
|
|
function updatePaperWidthFromFormat() {
|
|
const format = document.getElementById('paper_format').value;
|
|
const widthInput = document.getElementById('paper_width');
|
|
|
|
const widthMap = {
|
|
'58mm': 32,
|
|
'80mm': 48,
|
|
'letter': 80
|
|
};
|
|
|
|
if (widthMap[format]) {
|
|
widthInput.value = widthMap[format];
|
|
}
|
|
}
|
|
|
|
// Modal tab switching
|
|
function switchPrinterModalTab(tabName) {
|
|
// Update tab buttons
|
|
document.querySelectorAll('.printer-modal-tab-btn').forEach(btn => {
|
|
btn.classList.remove('active');
|
|
if (btn.getAttribute('data-tab') === tabName) {
|
|
btn.classList.add('active');
|
|
}
|
|
});
|
|
|
|
// Update tab content
|
|
document.querySelectorAll('.printer-modal-tab-content').forEach(content => {
|
|
content.classList.remove('active');
|
|
});
|
|
document.getElementById(tabName + '-tab-content').classList.add('active');
|
|
}
|
|
|
|
// Close printer modal
|
|
function closePrinterModal() {
|
|
hideModal('printerConfigModal');
|
|
currentPrinterId = null;
|
|
}
|
|
|
|
// Show modal
|
|
function showModal(modalId) {
|
|
document.getElementById(modalId).classList.add('visible');
|
|
}
|
|
|
|
// Hide modal
|
|
function hideModal(modalId) {
|
|
document.getElementById(modalId).classList.remove('visible');
|
|
}
|
|
|
|
// ========== Sound Notification Functions ==========
|
|
|
|
// Upload sound file
|
|
async function uploadSound(soundType) {
|
|
const fileInputId = soundType === 'newOrder' ? 'newOrderSoundUpload' : 'canceledOrderSoundUpload';
|
|
const fileInput = document.getElementById(fileInputId);
|
|
const file = fileInput.files[0];
|
|
|
|
if (!file) {
|
|
alert('Please select a file first');
|
|
return;
|
|
}
|
|
|
|
const validTypes = ['audio/mpeg', 'audio/mp3', 'audio/wav', 'audio/ogg'];
|
|
if (!validTypes.includes(file.type)) {
|
|
alert('Please select a valid audio file (MP3, WAV, or OGG)');
|
|
return;
|
|
}
|
|
|
|
if (file.size > 10 * 1024 * 1024) {
|
|
alert('File size must be less than 10MB');
|
|
return;
|
|
}
|
|
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
formData.append('soundType', soundType);
|
|
|
|
try {
|
|
const response = await fetch('/settings/upload-sound', {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (!data.error) {
|
|
alert('Sound uploaded successfully! Please save settings to apply changes.');
|
|
location.reload();
|
|
} else {
|
|
alert('Upload failed: ' + (data.message || 'Unknown error'));
|
|
}
|
|
} catch (error) {
|
|
console.error('Sound upload error:', error);
|
|
alert('Upload failed: Network error');
|
|
}
|
|
}
|
|
|
|
// Test sound playback
|
|
async function testSound(soundType) {
|
|
try {
|
|
// Get current settings
|
|
const response = await fetch('/api/notification-settings');
|
|
const data = await response.json();
|
|
|
|
if (data.error) {
|
|
alert('Failed to load sound settings');
|
|
return;
|
|
}
|
|
|
|
const soundPath = soundType === 'newOrder'
|
|
? (data.newOrderSoundPath || '/public/sounds/new-order-notification.mp3')
|
|
: (data.canceledOrderSoundPath || '/public/sounds/canceled-order-notification.mp3');
|
|
|
|
const volumeInput = document.getElementById('soundVolume');
|
|
const volume = volumeInput ? parseInt(volumeInput.value, 10) / 100 : 0.8;
|
|
|
|
const audio = new Audio(soundPath);
|
|
audio.volume = volume;
|
|
|
|
audio.play().catch(error => {
|
|
console.error('Failed to play sound:', error);
|
|
alert('Failed to play sound. Make sure the file exists and is a valid audio file.');
|
|
});
|
|
} catch (error) {
|
|
console.error('Test sound error:', error);
|
|
alert('Failed to test sound: ' + error.message);
|
|
}
|
|
}
|
|
|
|
// Update volume display
|
|
function updateVolumeDisplay() {
|
|
const volumeInput = document.getElementById('soundVolume');
|
|
const volumeValue = document.getElementById('volumeValue');
|
|
|
|
if (volumeInput && volumeValue) {
|
|
volumeValue.textContent = volumeInput.value;
|
|
}
|
|
}
|
|
|
|
// ========== Event Listeners ==========
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Load printers on settings page
|
|
if (document.getElementById('printer-cards-container')) {
|
|
loadPrinters();
|
|
}
|
|
|
|
// Printer modal tab switching
|
|
document.querySelectorAll('.printer-modal-tab-btn').forEach(btn => {
|
|
btn.addEventListener('click', function() {
|
|
switchPrinterModalTab(this.getAttribute('data-tab'));
|
|
});
|
|
});
|
|
|
|
// Connection type change handler
|
|
const typeSelect = document.getElementById('printer_type_select');
|
|
if (typeSelect) {
|
|
typeSelect.addEventListener('change', updateInterfaceHint);
|
|
}
|
|
|
|
// Paper format change handler
|
|
const formatSelect = document.getElementById('paper_format');
|
|
if (formatSelect) {
|
|
formatSelect.addEventListener('change', updatePaperWidthFromFormat);
|
|
}
|
|
|
|
// Volume slider handler
|
|
const volumeInput = document.getElementById('soundVolume');
|
|
if (volumeInput) {
|
|
volumeInput.addEventListener('input', updateVolumeDisplay);
|
|
}
|
|
|
|
// Update interface placeholder based on interface type (legacy support)
|
|
const interfaceSelect = document.getElementById('printerInterface');
|
|
const pathInput = document.getElementById('printerPath');
|
|
|
|
if (interfaceSelect && pathInput) {
|
|
interfaceSelect.addEventListener('change', function() {
|
|
const placeholders = {
|
|
'usb': '/dev/usb/lp0 (Linux) or COM1 (Windows)',
|
|
'network': '192.168.1.100:9100',
|
|
'serial': 'COM1 (Windows) or /dev/ttyS0 (Linux)'
|
|
};
|
|
|
|
pathInput.placeholder = placeholders[this.value] || 'Enter printer path';
|
|
});
|
|
}
|
|
});
|