Initial commit
This commit is contained in:
145
views/dashboard.ejs
Normal file
145
views/dashboard.ejs
Normal file
@@ -0,0 +1,145 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Kitchen Display - Kitchen Agent</title>
|
||||
<link rel="stylesheet" href="/public/css/style.css">
|
||||
</head>
|
||||
<body class="dashboard-page">
|
||||
<header class="main-header">
|
||||
<div class="header-content">
|
||||
<h1>Kitchen Display</h1>
|
||||
<div class="connection-status-bar" id="connectionStatusBar">
|
||||
<div class="connection-status-item" id="localConnectionStatus" title="Connection to local dashboard server">
|
||||
<span class="status-indicator status-checking"></span>
|
||||
<span class="status-text">Dashboard</span>
|
||||
<span class="status-label" id="localStatusLabel">Checking...</span>
|
||||
</div>
|
||||
<div class="connection-status-item" id="apiConnectionStatus" title="Connection to api.thinklink.ai">
|
||||
<span class="status-indicator status-checking"></span>
|
||||
<span class="status-text">API Server</span>
|
||||
<span class="status-label" id="apiStatusLabel">Checking...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<a href="/settings" class="btn btn-secondary">Settings</a>
|
||||
<a href="/auth/logout" class="btn btn-secondary">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<% if (showStats) { %>
|
||||
<div class="stats-bar" id="statsBar">
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">Total Today</div>
|
||||
<div class="stat-value" id="stat-total"><%= stats.total %></div>
|
||||
</div>
|
||||
<div class="stat-card stat-new">
|
||||
<div class="stat-label">New</div>
|
||||
<div class="stat-value" id="stat-new"><%= stats.new %></div>
|
||||
</div>
|
||||
<div class="stat-card stat-preparing">
|
||||
<div class="stat-label">Preparing</div>
|
||||
<div class="stat-value" id="stat-preparing"><%= stats.preparing %></div>
|
||||
</div>
|
||||
<div class="stat-card stat-ready">
|
||||
<div class="stat-label">Ready</div>
|
||||
<div class="stat-value" id="stat-ready"><%= stats.ready %></div>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<div class="dashboard-controls">
|
||||
<div class="filter-buttons">
|
||||
<button class="filter-btn active" data-filter="all">All Orders</button>
|
||||
<button class="filter-btn" data-filter="new">New</button>
|
||||
<button class="filter-btn" data-filter="preparing">Preparing</button>
|
||||
<button class="filter-btn" data-filter="ready">Ready</button>
|
||||
</div>
|
||||
<button class="btn btn-secondary sync-button" id="syncButton" onclick="manualSync()" title="Check for new orders now">
|
||||
<span class="sync-spinner"></span>
|
||||
<span class="sync-text">Sync Now</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="orders-container" id="ordersContainer">
|
||||
<div class="loading">Loading orders...</div>
|
||||
</div>
|
||||
|
||||
<!-- Status Change Confirmation Modal -->
|
||||
<div class="modal" id="statusChangeModal">
|
||||
<div class="modal-content status-modal-content">
|
||||
<div class="status-modal-icon" id="statusModalIcon">
|
||||
<!-- Icon will be set dynamically -->
|
||||
</div>
|
||||
<h2 id="statusModalTitle">Confirm Status Change</h2>
|
||||
<div class="status-modal-details">
|
||||
<div class="status-modal-row">
|
||||
<span class="status-modal-label">Order #:</span>
|
||||
<span class="status-modal-value" id="statusModalOrderId">-</span>
|
||||
</div>
|
||||
<div class="status-modal-row">
|
||||
<span class="status-modal-label">Customer:</span>
|
||||
<span class="status-modal-value" id="statusModalCustomer">-</span>
|
||||
</div>
|
||||
<div class="status-modal-row status-transition-row">
|
||||
<div class="status-transition">
|
||||
<span class="status-badge" id="statusModalFrom">-</span>
|
||||
<span class="status-arrow">→</span>
|
||||
<span class="status-badge" id="statusModalTo">-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="status-modal-message" id="statusModalMessage">
|
||||
Are you sure you want to change this order's status?
|
||||
</p>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-secondary" onclick="closeStatusChangeModal()">Cancel</button>
|
||||
<button class="btn btn-success status-confirm-btn" id="statusConfirmBtn" onclick="confirmStatusChange()">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cancel Modal -->
|
||||
<div class="modal" id="cancelModal">
|
||||
<div class="modal-content">
|
||||
<h2>Cancel Order</h2>
|
||||
<p>Are you sure you want to cancel this order?</p>
|
||||
<div class="form-group">
|
||||
<label for="cancelReason">Reason (optional):</label>
|
||||
<textarea id="cancelReason" rows="3" placeholder="Enter cancellation reason..."></textarea>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-secondary" onclick="closeCancelModal()">Cancel</button>
|
||||
<button class="btn btn-danger" onclick="confirmCancel()">Confirm Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Details Modal -->
|
||||
<div class="modal" id="detailsModal">
|
||||
<div class="modal-content modal-large">
|
||||
<div class="modal-header">
|
||||
<h2>Order Details</h2>
|
||||
<button class="close-btn" onclick="closeDetailsModal()">×</button>
|
||||
</div>
|
||||
<div id="orderDetailsContent">
|
||||
<!-- Content will be populated by JavaScript -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Notification -->
|
||||
<div class="toast" id="toast"></div>
|
||||
|
||||
<script>
|
||||
const config = {
|
||||
dashboardRefreshInterval: <%= config.dashboardRefreshInterval || 10000 %>
|
||||
};
|
||||
</script>
|
||||
<script src="/public/js/common.js"></script>
|
||||
<script src="/public/js/dashboard.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
80
views/login.ejs
Normal file
80
views/login.ejs
Normal file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login - Kitchen Agent</title>
|
||||
<link rel="stylesheet" href="/public/css/style.css">
|
||||
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
||||
</head>
|
||||
<body class="login-page">
|
||||
<div class="login-container">
|
||||
<div class="login-card">
|
||||
<h1>Kitchen Agent</h1>
|
||||
<h2>Login</h2>
|
||||
|
||||
<% if (error) { %>
|
||||
<div class="alert alert-error">
|
||||
<%= error %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<form action="/auth/login" method="POST" id="loginForm">
|
||||
<div class="form-group">
|
||||
<label for="login">Email</label>
|
||||
<input type="email" id="login" name="login" required autofocus>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-block" id="submitBtn">
|
||||
Login
|
||||
</button>
|
||||
|
||||
<!-- Invisible reCAPTCHA -->
|
||||
<div class="g-recaptcha"
|
||||
data-sitekey="<%= recaptchaSiteKey %>"
|
||||
data-callback="onRecaptchaSuccess"
|
||||
data-size="invisible">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="login-footer">
|
||||
<p>ThinkLink Kitchen Agent System</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const form = document.getElementById('loginForm');
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
|
||||
form.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = 'Logging in...';
|
||||
|
||||
// Execute reCAPTCHA
|
||||
grecaptcha.execute();
|
||||
});
|
||||
|
||||
function onRecaptchaSuccess(token) {
|
||||
// reCAPTCHA token obtained, submit form
|
||||
form.submit();
|
||||
}
|
||||
|
||||
// Reset button if reCAPTCHA fails
|
||||
window.addEventListener('load', function() {
|
||||
if (window.grecaptcha) {
|
||||
grecaptcha.ready(function() {
|
||||
console.log('reCAPTCHA ready');
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
523
views/settings.ejs
Normal file
523
views/settings.ejs
Normal file
@@ -0,0 +1,523 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Settings - Kitchen Agent</title>
|
||||
<link rel="stylesheet" href="/public/css/style.css">
|
||||
</head>
|
||||
<body class="settings-page">
|
||||
<header class="main-header">
|
||||
<div class="header-content">
|
||||
<h1>Settings</h1>
|
||||
<div class="header-actions">
|
||||
<a href="/dashboard" class="btn btn-secondary">Back to Dashboard</a>
|
||||
<a href="/auth/logout" class="btn btn-secondary">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="settings-container">
|
||||
<% if (message) { %>
|
||||
<div class="alert alert-success">
|
||||
<%= message %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<% if (error) { %>
|
||||
<div class="alert alert-error">
|
||||
<%= error %>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<div class="tabs">
|
||||
<button class="tab-btn active" data-tab="general">General</button>
|
||||
<button class="tab-btn" data-tab="printer">Printer</button>
|
||||
<button class="tab-btn" data-tab="template">Receipt Template</button>
|
||||
</div>
|
||||
|
||||
<form action="/settings/save" method="POST" id="settingsForm">
|
||||
|
||||
<!-- General Settings Tab -->
|
||||
<div class="tab-content active" id="general-tab">
|
||||
<h2>General Settings</h2>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="selectedBotId">Select Bot/Assistant</label>
|
||||
<select id="selectedBotId" name="selectedBotId" required>
|
||||
<option value="">-- Select Bot --</option>
|
||||
<% bots.forEach(bot => { %>
|
||||
<% const botConfig = JSON.parse(bot.bot_config || '{}'); %>
|
||||
<option value="<%= bot.id %>" <%= config.selectedBotId == bot.id ? 'selected' : '' %>>
|
||||
<%= botConfig.name || 'Bot #' + bot.id %>
|
||||
</option>
|
||||
<% }); %>
|
||||
</select>
|
||||
<small>Select which bot's orders to display</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pollingInterval">Order Polling Interval (milliseconds)</label>
|
||||
<input type="number" id="pollingInterval" name="pollingInterval"
|
||||
value="<%= config.pollingInterval || 15000 %>" min="5000" max="60000" step="1000">
|
||||
<small>How often to check for new orders (default: 15000 = 15 seconds)</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="dashboardRefreshInterval">Dashboard Refresh Interval (milliseconds)</label>
|
||||
<input type="number" id="dashboardRefreshInterval" name="dashboardRefreshInterval"
|
||||
value="<%= config.dashboardRefreshInterval || 10000 %>" min="5000" max="60000" step="1000">
|
||||
<small>How often to refresh the dashboard display (default: 10000 = 10 seconds)</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" name="showOrderStats" <%= config.showOrderStats !== 'false' ? 'checked' : '' %>>
|
||||
Show Order Statistics Bar
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<h3 style="margin-top: 30px; margin-bottom: 15px; border-top: 2px solid #e0e0e0; padding-top: 20px;">Sound Notifications</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="soundNotificationsEnabled" name="soundNotificationsEnabled" <%= config.soundNotificationsEnabled !== 'false' ? 'checked' : '' %>>
|
||||
Enable Sound Notifications
|
||||
</label>
|
||||
<small>Play sounds when new orders arrive or orders are canceled</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="soundVolume">Notification Volume</label>
|
||||
<input type="range" id="soundVolume" name="soundVolume" min="0" max="100" value="<%= config.soundVolume || 80 %>" style="width: 100%;">
|
||||
<small>Volume: <span id="volumeValue"><%= config.soundVolume || 80 %></span>%</small>
|
||||
</div>
|
||||
|
||||
<div class="settings-section" style="background: #f9f9f9; padding: 20px; border-radius: 8px; margin-top: 20px;">
|
||||
<h4 style="margin-top: 0;">New Order Sound</h4>
|
||||
<div class="form-group">
|
||||
<label>Current Sound File:</label>
|
||||
<p style="font-size: 14px; color: #666;">
|
||||
<%= config.newOrderSoundPath || '/public/sounds/new-order-notification.mp3' %>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Upload Custom Sound (optional)</label>
|
||||
<input type="file" id="newOrderSoundUpload" accept="audio/*">
|
||||
<button type="button" class="btn btn-secondary" onclick="uploadSound('newOrder')">Upload New Order Sound</button>
|
||||
<button type="button" class="btn btn-secondary" onclick="testSound('newOrder')">🔊 Test Sound</button>
|
||||
<small>Supported formats: MP3, WAV, OGG</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section" style="background: #f9f9f9; padding: 20px; border-radius: 8px; margin-top: 20px;">
|
||||
<h4 style="margin-top: 0;">Canceled Order Sound</h4>
|
||||
<div class="form-group">
|
||||
<label>Current Sound File:</label>
|
||||
<p style="font-size: 14px; color: #666;">
|
||||
<%= config.canceledOrderSoundPath || '/public/sounds/canceled-order-notification.mp3' %>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Upload Custom Sound (optional)</label>
|
||||
<input type="file" id="canceledOrderSoundUpload" accept="audio/*">
|
||||
<button type="button" class="btn btn-secondary" onclick="uploadSound('canceled')">Upload Canceled Sound</button>
|
||||
<button type="button" class="btn btn-secondary" onclick="testSound('canceled')">🔊 Test Sound</button>
|
||||
<small>Supported formats: MP3, WAV, OGG</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Printer Management Tab -->
|
||||
<div class="tab-content" id="printer-tab">
|
||||
<h2>Printer Management</h2>
|
||||
<p class="section-description">Configure individual printers with specific paper sizes, templates, and settings.</p>
|
||||
|
||||
<div class="settings-section">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
||||
<h3 style="margin: 0;">Configured Printers</h3>
|
||||
<button type="button" class="btn btn-primary" onclick="openAddPrinterModal()">+ Add Printer</button>
|
||||
</div>
|
||||
|
||||
<div id="printer-cards-container" class="printer-cards-container">
|
||||
<!-- Printer cards will be loaded here dynamically -->
|
||||
<div class="loading">Loading printers...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Receipt Template Tab -->
|
||||
<div class="tab-content" id="template-tab">
|
||||
<h2>Receipt Template</h2>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="headerText">Header Text</label>
|
||||
<textarea id="headerText" name="headerText" rows="2" placeholder="KITCHEN ORDER"><%= typeof config.headerText !== 'undefined' ? config.headerText : '' %></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="footerText">Footer Text</label>
|
||||
<textarea id="footerText" name="footerText" rows="2" placeholder="Thank you!"><%= typeof config.footerText !== 'undefined' ? config.footerText : '' %></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" name="qrCodeEnabled" <%= config.qrCodeEnabled !== 'false' ? 'checked' : '' %>>
|
||||
Print QR Code on Receipt
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="qrCodeSize">QR Code Size</label>
|
||||
<input type="number" id="qrCodeSize" name="qrCodeSize" min="2" max="8" value="<%= config.qrCodeSize || 3 %>">
|
||||
<small>Cell size (2–8). Larger = bigger QR.</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="qrCodeCorrection">QR Error Correction</label>
|
||||
<select id="qrCodeCorrection" name="qrCodeCorrection">
|
||||
<option value="L" <%= (config.qrCodeCorrection || 'M') === 'L' ? 'selected' : '' %>>L (Low)</option>
|
||||
<option value="M" <%= (config.qrCodeCorrection || 'M') === 'M' ? 'selected' : '' %>>M (Medium)</option>
|
||||
<option value="Q" <%= (config.qrCodeCorrection || 'M') === 'Q' ? 'selected' : '' %>>Q (Quartile)</option>
|
||||
<option value="H" <%= (config.qrCodeCorrection || 'M') === 'H' ? 'selected' : '' %>>H (High)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="qrCodeContentTemplate">QR Content Template</label>
|
||||
<input type="text" id="qrCodeContentTemplate" name="qrCodeContentTemplate" value="<%= config.qrCodeContentTemplate || 'ORDER-{id}' %>">
|
||||
<small>Use placeholders: {id}, {total}, {type}, {createdAt}</small>
|
||||
</div>
|
||||
|
||||
<h3>Show/Hide Sections</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" name="showCustomerInfo" <%= config.showCustomerInfo !== 'false' ? 'checked' : '' %>>
|
||||
Show Customer Information
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" name="showOrderItems" <%= config.showOrderItems !== 'false' ? 'checked' : '' %>>
|
||||
Show Order Items
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" name="showPrices" <%= config.showPrices !== 'false' ? 'checked' : '' %>>
|
||||
Show Prices
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" name="showTimestamps" <%= config.showTimestamps !== 'false' ? 'checked' : '' %>>
|
||||
Show Timestamps
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Logo Image (optional)</label>
|
||||
<input type="file" id="logoUpload" accept="image/*">
|
||||
<button type="button" class="btn btn-secondary" onclick="uploadLogo()">Upload Logo</button>
|
||||
<small>Upload a logo image to print at the top of receipts</small>
|
||||
<% if (config.logoPath) { %>
|
||||
<div class="current-logo">
|
||||
<p>Current logo: <%= config.logoPath %></p>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<h3>Business Information</h3>
|
||||
<div class="form-group">
|
||||
<label for="businessName">Business Name</label>
|
||||
<input type="text" id="businessName" name="businessName" value="<%= config.businessName || '' %>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="businessAddress">Address</label>
|
||||
<input type="text" id="businessAddress" name="businessAddress" value="<%= config.businessAddress || '' %>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="businessPhone">Phone</label>
|
||||
<input type="text" id="businessPhone" name="businessPhone" value="<%= config.businessPhone || '' %>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="businessWebsite">Website</label>
|
||||
<input type="text" id="businessWebsite" name="businessWebsite" value="<%= config.businessWebsite || '' %>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="businessEmail">Email</label>
|
||||
<input type="text" id="businessEmail" name="businessEmail" value="<%= config.businessEmail || '' %>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="businessContactSize">Contact Font Size</label>
|
||||
<select id="businessContactSize" name="businessContactSize">
|
||||
<option value="normal" <%= (config.businessContactSize || 'normal') === 'normal' ? 'selected' : '' %>>Normal</option>
|
||||
<option value="large" <%= (config.businessContactSize || 'normal') === 'large' ? 'selected' : '' %>>Large</option>
|
||||
</select>
|
||||
<small>Controls the size of address/phone/website/email in header.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary btn-large">Save All Settings</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Printer Configuration Modal -->
|
||||
<div class="modal" id="printerConfigModal">
|
||||
<div class="modal-content modal-large">
|
||||
<div class="modal-header">
|
||||
<h2 id="printerModalTitle">Add Printer</h2>
|
||||
<button class="close-btn" onclick="closePrinterModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div class="printer-modal-body">
|
||||
<div class="printer-modal-tabs">
|
||||
<button class="printer-modal-tab-btn active" data-tab="connection">Connection</button>
|
||||
<button class="printer-modal-tab-btn" data-tab="paper">Paper & Format</button>
|
||||
<button class="printer-modal-tab-btn" data-tab="template">Template</button>
|
||||
<button class="printer-modal-tab-btn" data-tab="business">Business Info</button>
|
||||
<button class="printer-modal-tab-btn" data-tab="logo">Logo & Branding</button>
|
||||
<button class="printer-modal-tab-btn" data-tab="qrcode">QR Code</button>
|
||||
</div>
|
||||
|
||||
<form id="printerConfigForm" onsubmit="return false;">
|
||||
<input type="hidden" id="printer_id" name="id">
|
||||
|
||||
<!-- Connection Tab -->
|
||||
<div class="printer-modal-tab-content active" id="connection-tab-content">
|
||||
<div class="form-group">
|
||||
<label for="printer_name">Printer Name *</label>
|
||||
<input type="text" id="printer_name" name="name" required placeholder="e.g., Kitchen Printer - 80mm">
|
||||
<small>Give this printer a descriptive name</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="printer_type_select">Connection Type *</label>
|
||||
<select id="printer_type_select" name="type" required>
|
||||
<option value="network">Network (TCP/IP)</option>
|
||||
<option value="com">Serial Port (COM)</option>
|
||||
<option value="usb">USB</option>
|
||||
<option value="system">Windows System Printer</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="printer_interface">Connection Address *</label>
|
||||
<input type="text" id="printer_interface" name="interface" required placeholder="e.g., 192.168.1.100:9100, COM1, /dev/usb/lp0">
|
||||
<small id="interface_hint">Enter IP:Port for network printers</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="button" class="btn btn-secondary" onclick="detectPrintersForModal()">Detect Available Printers</button>
|
||||
<div id="detected-printers-list" style="margin-top: 10px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Paper & Format Tab -->
|
||||
<div class="printer-modal-tab-content" id="paper-tab-content">
|
||||
<div class="form-group">
|
||||
<label for="paper_format">Paper Format *</label>
|
||||
<select id="paper_format" name="paper_format" required>
|
||||
<option value="58mm">58mm Thermal</option>
|
||||
<option value="80mm" selected>80mm Thermal</option>
|
||||
<option value="letter">Letter Size (8.5 x 11)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="paper_width">Character Width *</label>
|
||||
<input type="number" id="paper_width" name="paper_width" value="48" min="20" max="100" required>
|
||||
<small>58mm: 32 chars | 80mm: 48 chars | Letter: 80+ chars</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="printer_type_model">Printer Model/Brand *</label>
|
||||
<select id="printer_type_model" name="printer_type" required>
|
||||
<option value="epson" selected>Epson</option>
|
||||
<option value="star">Star</option>
|
||||
<option value="tanca">Tanca</option>
|
||||
<option value="brother">Brother</option>
|
||||
<option value="custom">Custom</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="font_size">Font Size</label>
|
||||
<select id="font_size" name="font_size">
|
||||
<option value="small">Small</option>
|
||||
<option value="normal" selected>Normal</option>
|
||||
<option value="large">Large</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="line_style">Line Style</label>
|
||||
<select id="line_style" name="line_style">
|
||||
<option value="single" selected>Single (─)</option>
|
||||
<option value="double">Double (═)</option>
|
||||
<option value="dashed">Dashed (- -)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Template Tab -->
|
||||
<div class="printer-modal-tab-content" id="template-tab-content">
|
||||
<div class="form-group">
|
||||
<label for="header_text">Header Text</label>
|
||||
<textarea id="header_text" name="header_text" rows="2" placeholder="KITCHEN ORDER"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="footer_text">Footer Text</label>
|
||||
<textarea id="footer_text" name="footer_text" rows="2" placeholder="Thank you!"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="show_customer_info" name="show_customer_info" checked>
|
||||
Show Customer Information
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="show_order_items" name="show_order_items" checked>
|
||||
Show Order Items
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="show_prices" name="show_prices" checked>
|
||||
Show Prices
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="show_timestamps" name="show_timestamps" checked>
|
||||
Show Timestamps
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Business Info Tab -->
|
||||
<div class="printer-modal-tab-content" id="business-tab-content">
|
||||
<div class="form-group">
|
||||
<label for="business_name">Business Name</label>
|
||||
<input type="text" id="business_name" name="business_name" placeholder="Your Business Name">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="business_address">Address</label>
|
||||
<input type="text" id="business_address" name="business_address" placeholder="123 Main St, City, State ZIP">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="business_phone">Phone</label>
|
||||
<input type="text" id="business_phone" name="business_phone" placeholder="(555) 123-4567">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="business_website">Website</label>
|
||||
<input type="text" id="business_website" name="business_website" placeholder="www.example.com">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="business_email">Email</label>
|
||||
<input type="email" id="business_email" name="business_email" placeholder="contact@example.com">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="business_contact_size">Contact Info Size</label>
|
||||
<select id="business_contact_size" name="business_contact_size">
|
||||
<option value="normal" selected>Normal</option>
|
||||
<option value="large">Large</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Logo & Branding Tab -->
|
||||
<div class="printer-modal-tab-content" id="logo-tab-content">
|
||||
<div class="form-group">
|
||||
<label>Logo Image</label>
|
||||
<input type="file" id="logo_upload_modal" accept="image/*">
|
||||
<button type="button" class="btn btn-secondary" onclick="uploadLogoForPrinter()" style="margin-top: 10px;">Upload Logo</button>
|
||||
<small>Upload a logo for this specific printer</small>
|
||||
<div id="logo_preview" style="margin-top: 10px;"></div>
|
||||
<input type="hidden" id="logo_path" name="logo_path">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="logo_max_width_dots">Logo Max Width (dots)</label>
|
||||
<input type="number" id="logo_max_width_dots" name="logo_max_width_dots" min="100" max="800" placeholder="Auto-detect based on paper width">
|
||||
<small>58mm: ~384 dots | 80mm: ~576 dots | Leave empty for auto</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- QR Code Tab -->
|
||||
<div class="printer-modal-tab-content" id="qrcode-tab-content">
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="qr_code_enabled" name="qr_code_enabled" checked>
|
||||
Print QR Code on Receipt
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="qr_code_size">QR Code Size</label>
|
||||
<input type="number" id="qr_code_size" name="qr_code_size" value="3" min="2" max="8">
|
||||
<small>Cell size (2-8). Larger = bigger QR code</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="qr_code_correction">Error Correction Level</label>
|
||||
<select id="qr_code_correction" name="qr_code_correction">
|
||||
<option value="L">L (Low - 7% recovery)</option>
|
||||
<option value="M" selected>M (Medium - 15% recovery)</option>
|
||||
<option value="Q">Q (Quartile - 25% recovery)</option>
|
||||
<option value="H">H (High - 30% recovery)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="qr_code_content_template">QR Content Template</label>
|
||||
<input type="text" id="qr_code_content_template" name="qr_code_content_template" value="ORDER-{id}" placeholder="ORDER-{id}">
|
||||
<small>Use: {id}, {total}, {type}, {createdAt}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-actions" style="margin-top: 30px; padding-top: 20px; border-top: 2px solid #e0e0e0;">
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="is_default" name="is_default">
|
||||
Set as Default Printer
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="is_enabled" name="is_enabled" checked>
|
||||
Enabled (Print to this printer)
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" class="btn btn-secondary" onclick="closePrinterModal()">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary" onclick="savePrinterConfig()">Save Printer</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/public/js/common.js"></script>
|
||||
<script src="/public/js/settings.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user