487 lines
22 KiB
HTML
487 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<base target="_top">
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<meta name="theme-color" content="#111111">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<title>POS - DAPUR</title>
|
|
<style>
|
|
body { margin:0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background:#f4f7f6; padding: 12px; -webkit-font-smoothing: antialiased; }
|
|
.nav { background:#111; color:white; padding:12px; border-radius:12px; margin-bottom:15px; display:flex; justify-content:space-between; align-items:center; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
|
|
.title { font-weight:800; letter-spacing:0.5px; font-size: 14px; }
|
|
.btn-refresh { background:#e11d48; color:white; border:none; padding:10px 15px; border-radius:10px; font-weight:800; cursor:pointer; font-size: 12px; }
|
|
.btn-refresh:active { opacity: 0.7; }
|
|
|
|
.dapur-grid { display:grid; grid-template-columns: 1fr; gap:12px; }
|
|
@media (min-width: 768px) { .dapur-grid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } }
|
|
|
|
.trans-card { background:white; border:1px solid #eee; border-radius:12px; padding:15px; position:relative; transform: translateZ(0); }
|
|
.title-sm { font-weight:800; color:#111; margin-bottom:10px; font-size:14px; }
|
|
.muted { color:#777; font-size:11px; }
|
|
|
|
.item-row { display:flex; justify-content:space-between; align-items: center; padding:10px 0; border-bottom:1px solid #f3f4f6; }
|
|
.item-nama { font-weight:800; font-size:15px; color: #111; }
|
|
.item-qty { font-weight:900; font-size:20px; color:#e11d48; }
|
|
.item-qty.prio { color:#16a34a; }
|
|
|
|
.btn-selesai { width:100%; padding:14px; border:none; border-radius:12px; background:#111; color:white; font-weight:800; cursor:pointer; margin-top:12px; font-size: 14px; }
|
|
.btn-selesai.prio { background:#16a34a; }
|
|
.btn-selesai:active { opacity: 0.7; }
|
|
.btn-print { width:100%; padding:14px; border:none; border-radius:12px; background:#444; color:white; font-weight:800; cursor:pointer; margin-top:12px; font-size: 14px; }
|
|
.btn-print:active { opacity: 0.7; }
|
|
|
|
#sync-indicator { position:fixed; top:15px; right:15px; background:rgba(0,0,0,0.8); color:white; padding:6px 12px; border-radius:20px; font-size:11px; display:none; z-index: 1000; font-weight: 800; }
|
|
|
|
#audio-permission { position:fixed; inset:0; background:rgba(0,0,0,0.9); z-index:2000; display:none; flex-direction:column; justify-content:center; align-items:center; color:white; text-align:center; padding:20px; }
|
|
.btn-audio { background:#16a34a; color:white; border:none; padding:15px 30px; border-radius:12px; font-weight:800; font-size:16px; cursor:pointer; margin-top:20px; }
|
|
|
|
::-webkit-scrollbar { width: 4px; }
|
|
::-webkit-scrollbar-thumb { background: #ddd; border-radius: 10px; }
|
|
|
|
.modal { position:fixed; inset:0; background:rgba(0,0,0,0.6); display:none; align-items:flex-end; z-index:1500; }
|
|
.modal .sheet { background:white; width:100%; border-top-left-radius:24px; border-top-right-radius:24px; padding:20px; max-height:90vh; overflow-y:auto; box-sizing: border-box; }
|
|
.modal .close { font-weight:800; cursor:pointer; color: #e11d48; padding: 5px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="nav">
|
|
<div class="title" id="store-title">DAPUR</div>
|
|
<div style="display:flex; gap:10px;">
|
|
<button class="btn-refresh" onclick="openChatModal()">CHAT</button>
|
|
<button class="btn-refresh" onclick="triggerBellDapur()">PANGGIL KASIR</button>
|
|
<button class="btn-refresh" onclick="syncData()">REFRESH PESANAN</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="audio-permission">
|
|
<div style="font-weight:800; font-size:20px;">🔔 AKTIFKAN SUARA NOTIFIKASI</div>
|
|
<p style="opacity:0.8; margin-top:10px;">Klik tombol di bawah agar HP bisa mengeluarkan bunyi pip saat ada pesanan masuk.</p>
|
|
<button class="btn-audio" onclick="enableAudio()">AKTIFKAN SEKARANG</button>
|
|
</div>
|
|
|
|
<div id="sync-indicator">⌛ Syncing...</div>
|
|
|
|
<div id="dapur-content">
|
|
<div class="title-sm" style="color:#16a34a; font-size:18px;">⚡ PRIORITAS: DRINKS, NASI & TOMYUM</div>
|
|
<div id="list-prio" class="dapur-grid" style="margin-bottom:30px;"></div>
|
|
|
|
<div class="title-sm" style="color:#e11d48; font-size:18px;">🥘 MENU UTAMA / GRILL</div>
|
|
<div id="list-main" class="dapur-grid"></div>
|
|
</div>
|
|
|
|
<div id="modal" class="modal" onclick="if(event.target.id==='modal') closeModal()">
|
|
<div class="sheet">
|
|
<div style="display:flex; justify-content:space-between; align-items:center;">
|
|
<div class="title-sm" style="margin:0;">Info</div>
|
|
<div class="close" onclick="closeModal()">TUTUP</div>
|
|
</div>
|
|
<div id="modal-body"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
var transaksi = [];
|
|
var menu = [];
|
|
var audioContext = null;
|
|
var beepInterval = null;
|
|
var chatBeepInterval = null;
|
|
var lastChatCount = 0;
|
|
|
|
window.onload = function() {
|
|
initAutoAudioUnlock();
|
|
syncData();
|
|
setInterval(syncData, 15000); // Auto refresh lebih cepat (15 detik)
|
|
setInterval(checkNewChat, 10000); // Polling chat global
|
|
};
|
|
|
|
function initAutoAudioUnlock() {
|
|
try { enableAudio(); } catch(e) {}
|
|
var once = function() {
|
|
try { enableAudio(); } catch(e) {}
|
|
document.removeEventListener('pointerdown', once, true);
|
|
document.removeEventListener('touchstart', once, true);
|
|
document.removeEventListener('click', once, true);
|
|
document.removeEventListener('keydown', once, true);
|
|
};
|
|
document.addEventListener('pointerdown', once, true);
|
|
document.addEventListener('touchstart', once, true);
|
|
document.addEventListener('click', once, true);
|
|
document.addEventListener('keydown', once, true);
|
|
}
|
|
|
|
function checkNewChat() {
|
|
google.script.run.withSuccessHandler(function(messages) {
|
|
// Cari apakah ada pesan baru dari Kasir yang belum dibaca
|
|
var unreadFromKasir = messages.some(function(m) {
|
|
return m.sender === 'Kasir' && m.status === 'Belum Dibaca';
|
|
});
|
|
|
|
if (unreadFromKasir) {
|
|
if (!chatBeepInterval) {
|
|
playChatSound(); // Bunyi langsung sekali
|
|
chatBeepInterval = setInterval(playChatSound, 3000); // Ulang tiap 3 detik
|
|
}
|
|
} else {
|
|
if (chatBeepInterval) {
|
|
clearInterval(chatBeepInterval);
|
|
chatBeepInterval = null;
|
|
}
|
|
}
|
|
|
|
lastChatCount = messages.length;
|
|
|
|
// Jika modal chat sedang terbuka, update UI dan tandai sudah dibaca
|
|
if (document.getElementById('chat-messages')) {
|
|
renderChatList(messages);
|
|
google.script.run.markChatAsRead('Dapur');
|
|
}
|
|
}).getChatMessages();
|
|
}
|
|
|
|
function enableAudio() {
|
|
if (!audioContext) {
|
|
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
}
|
|
document.getElementById('audio-permission').style.display = 'none';
|
|
// Play silent buffer to unlock audio on iOS
|
|
var buffer = audioContext.createBuffer(1, 1, 22050);
|
|
var source = audioContext.createBufferSource();
|
|
source.buffer = buffer;
|
|
source.connect(audioContext.destination);
|
|
source.start(0);
|
|
}
|
|
|
|
function playBeep() {
|
|
if (!audioContext) return;
|
|
var osc = audioContext.createOscillator();
|
|
var gain = audioContext.createGain();
|
|
// Menggunakan 'triangle' agar suara lebih padat dan keras dibanding 'sine'
|
|
osc.type = 'triangle';
|
|
osc.frequency.setValueAtTime(1000, audioContext.currentTime); // Frekuensi lebih tinggi (lebih tajam)
|
|
|
|
// Volume ditingkatkan ke 0.8 (dari 0.1)
|
|
gain.gain.setValueAtTime(0.8, audioContext.currentTime);
|
|
gain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.8);
|
|
|
|
osc.connect(gain);
|
|
gain.connect(audioContext.destination);
|
|
osc.start();
|
|
osc.stop(audioContext.currentTime + 0.8);
|
|
}
|
|
|
|
function playChatSound() {
|
|
if (!audioContext) return;
|
|
// Nada ding-ding cepat
|
|
[0, 0.15].forEach(function(delay) {
|
|
var osc = audioContext.createOscillator();
|
|
var gain = audioContext.createGain();
|
|
osc.type = 'sine';
|
|
osc.frequency.setValueAtTime(1500, audioContext.currentTime + delay);
|
|
gain.gain.setValueAtTime(0.5, audioContext.currentTime + delay);
|
|
gain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + delay + 0.1);
|
|
osc.connect(gain);
|
|
gain.connect(audioContext.destination);
|
|
osc.start(audioContext.currentTime + delay);
|
|
osc.stop(audioContext.currentTime + delay + 0.1);
|
|
});
|
|
}
|
|
|
|
function syncData() {
|
|
document.getElementById('sync-indicator').style.display = 'block';
|
|
google.script.run.withSuccessHandler(function(res) {
|
|
document.getElementById('sync-indicator').style.display = 'none';
|
|
transaksi = res.transaksi || [];
|
|
menu = res.menu || [];
|
|
if (res && res.settings && res.settings.store_name) {
|
|
var storeName = String(res.settings.store_name || 'POS');
|
|
var el = document.getElementById('store-title');
|
|
if (el) el.innerText = storeName + ' - DAPUR';
|
|
try { document.title = storeName + ' - DAPUR'; } catch(e) {}
|
|
}
|
|
renderDapur();
|
|
}).withFailureHandler(function(err) {
|
|
document.getElementById('sync-indicator').style.display = 'none';
|
|
alert('Gagal sinkronisasi dapur.\n' + (err && err.message ? err.message : err));
|
|
}).getInitialData();
|
|
}
|
|
|
|
function renderDapur() {
|
|
var boxPrio = document.getElementById('list-prio');
|
|
var boxMain = document.getElementById('list-main');
|
|
boxPrio.innerHTML = '';
|
|
boxMain.innerHTML = '';
|
|
|
|
var today = new Date().toISOString().split('T')[0];
|
|
|
|
// Logika pencarian pesanan aktif (status Pending)
|
|
var list = transaksi.filter(function(t) {
|
|
// Normalisasi status (mungkin case sensitive)
|
|
var status = String(t.status || '').trim();
|
|
var isPending = (status === 'Pending' || status === 'PENDING');
|
|
|
|
// Normalisasi tanggal (untuk filter hari ini saja)
|
|
var tgl = "";
|
|
if (t.timestamp) {
|
|
tgl = t.timestamp.split(' ')[0];
|
|
} else if (t.tgl) {
|
|
tgl = (t.tgl instanceof Date) ? t.tgl.toISOString().split('T')[0] : String(t.tgl).split(' ')[0];
|
|
}
|
|
|
|
var isToday = (tgl === today);
|
|
|
|
return isPending && isToday;
|
|
});
|
|
|
|
var shouldMuteSound = function(t) {
|
|
var nama = String((t && t.nama) || '').trim();
|
|
return /x123/i.test(nama);
|
|
};
|
|
|
|
// Bunyi Pip berulang jika ada pesanan masuk
|
|
var beepList = list.filter(function(t) { return !shouldMuteSound(t); });
|
|
if (beepList.length > 0) {
|
|
if (!beepInterval) {
|
|
playBeep(); // Bunyi langsung sekali
|
|
beepInterval = setInterval(playBeep, 3000); // Ulang tiap 3 detik
|
|
}
|
|
} else {
|
|
if (beepInterval) {
|
|
clearInterval(beepInterval);
|
|
beepInterval = null;
|
|
}
|
|
}
|
|
|
|
// Tampilkan pesan jika kosong
|
|
|
|
if (!list.length) {
|
|
boxMain.innerHTML = '<div style="text-align:center; grid-column:1/-1; padding:50px; color:#aaa;">Belum ada pesanan aktif.</div>';
|
|
return;
|
|
}
|
|
|
|
list.forEach(function(t) {
|
|
var items = t.items || [];
|
|
|
|
// Pisahkan item prioritas (Drinks, Nasi & Kuah Tomyum di Ala Carte)
|
|
var prioItems = items.filter(function(it) {
|
|
var n = it.nama.toLowerCase();
|
|
var k = it.kat || (menu.find(function(m) { return m.nama === it.nama; }) || {}).kategori || '';
|
|
return (k === 'Drinks') || (k === 'Ala Carte' && (n.includes('nasi') || n.includes('kuah tomyum')));
|
|
});
|
|
|
|
var mainItems = items.filter(function(it) {
|
|
var n = it.nama.toLowerCase();
|
|
var k = it.kat || (menu.find(function(m) { return m.nama === it.nama; }) || {}).kategori || '';
|
|
var isPrio = (k === 'Drinks') || (k === 'Ala Carte' && (n.includes('nasi') || n.includes('kuah tomyum')));
|
|
return !isPrio;
|
|
});
|
|
|
|
// Render kartu Prioritas jika ada
|
|
if (prioItems.length > 0) {
|
|
boxPrio.appendChild(createCard(t, prioItems, true));
|
|
}
|
|
|
|
// Render kartu Utama jika ada
|
|
if (mainItems.length > 0) {
|
|
boxMain.appendChild(createCard(t, mainItems, false));
|
|
}
|
|
});
|
|
}
|
|
|
|
function createCard(t, items, isPrio) {
|
|
var div = document.createElement('div');
|
|
div.className = 'trans-card';
|
|
if (isPrio) div.style.borderLeft = '6px solid #16a34a';
|
|
else div.style.borderLeft = '6px solid #e11d48';
|
|
|
|
var mejaText = String(t.meja || '').trim();
|
|
if (mejaText.toLowerCase().indexOf('meja') === 0) {
|
|
mejaText = mejaText.replace(/^\s*meja\s*/i, '').trim();
|
|
}
|
|
mejaText = mejaText || '?';
|
|
|
|
var itemsHtml = '';
|
|
items.forEach(function(it) {
|
|
itemsHtml += '<div class="item-row">' +
|
|
'<div class="item-nama">' + (isPrio ? '🥤 ' : '🍲 ') + it.nama + '</div>' +
|
|
'<div class="item-qty ' + (isPrio ? 'prio' : '') + '">x' + it.qty + '</div>' +
|
|
'</div>';
|
|
});
|
|
|
|
var catatanHtml = '';
|
|
if (t.catatan) {
|
|
catatanHtml = '<div style="margin-top:10px; padding:8px; background:#fff7ed; border:1px dashed #fb923c; border-radius:8px; font-size:12px; color:#9a3412;">' +
|
|
'<b>Catatan:</b> ' + t.catatan +
|
|
'</div>';
|
|
}
|
|
|
|
div.innerHTML = '<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:10px; border-bottom:2px solid #eee; padding-bottom:8px; gap:10px;">' +
|
|
'<div style="display:flex; flex-direction:column; gap:2px;">' +
|
|
'<div style="font-weight:900; font-size:20px;">Meja ' + mejaText + '</div>' +
|
|
'<div style="font-size:12px; font-weight:800; color:#111;">' + (t.nama ? t.nama : '-') + '</div>' +
|
|
'</div>' +
|
|
'<div class="muted" style="white-space:nowrap;">' + (t.timestamp ? t.timestamp.split(' ')[1] : '') + '</div>' +
|
|
'</div>' +
|
|
'<div>' + itemsHtml + '</div>' +
|
|
catatanHtml +
|
|
'<div style="display:flex; gap:10px; margin-top:12px;">' +
|
|
'<button class="btn-print" style="flex:1; margin-top:0;" onclick="cetakStrukDapur(\'' + t.id + '\', ' + (isPrio ? 'true' : 'false') + ')">CETAK</button>' +
|
|
'<button class="btn-selesai ' + (isPrio ? 'prio' : '') + '" style="flex:1; margin-top:0;" onclick="tandaiSelesai(\'' + t.id + '\')">TANDAI SELESAI</button>' +
|
|
'</div>';
|
|
return div;
|
|
}
|
|
|
|
function cetakStrukDapur(id, isPrio) {
|
|
var t = transaksi.find(function(x) { return String(x.id) === String(id); });
|
|
if (!t) { alert('Transaksi tidak ditemukan.'); return; }
|
|
var items = Array.isArray(t.items) ? t.items : [];
|
|
|
|
var filtered = items.filter(function(it) {
|
|
var n = String(it.nama || '').toLowerCase();
|
|
var k = it.kat || (menu.find(function(m) { return m.nama === it.nama; }) || {}).kategori || '';
|
|
var prio = (k === 'Drinks') || (k === 'Ala Carte' && (n.indexOf('nasi') > -1 || n.indexOf('kuah tomyum') > -1));
|
|
return isPrio ? prio : !prio;
|
|
});
|
|
|
|
var mejaText = String(t.meja || '').trim();
|
|
if (mejaText.toLowerCase().indexOf('meja') === 0) mejaText = mejaText.replace(/^\s*meja\s*/i, '').trim();
|
|
mejaText = mejaText || '?';
|
|
|
|
var lines = [];
|
|
lines.push('MEJA ' + mejaText);
|
|
if (t.nama) lines.push(String(t.nama));
|
|
lines.push('------------------------------');
|
|
filtered.forEach(function(it) {
|
|
var qty = Number(it.qty || 0) || 0;
|
|
var name = String(it.nama || '');
|
|
if (qty <= 0 || !name) return;
|
|
lines.push('x' + qty + ' ' + name);
|
|
});
|
|
if (t.catatan) {
|
|
lines.push('------------------------------');
|
|
lines.push('CATATAN: ' + String(t.catatan));
|
|
}
|
|
|
|
var text = lines.join('\n');
|
|
|
|
var isAndroid = /Android/i.test(navigator.userAgent || '');
|
|
if (isAndroid) {
|
|
var url = 'rawbt:' + encodeURIComponent(text + '\n\n');
|
|
window.location.href = url;
|
|
return;
|
|
}
|
|
|
|
var w = window.open('', '_blank', 'width=320,height=600');
|
|
if (!w) {
|
|
alert(text);
|
|
return;
|
|
}
|
|
var doc = '<html><head><style>' +
|
|
'@media print { @page { margin: 0; size: 58mm auto; } body { margin: 0; padding: 0; } }' +
|
|
'body { font-family: \"Courier New\", Courier, monospace; width: 48mm; margin: 0; padding: 0; font-size: 10pt; line-height: 1.1; white-space: pre-wrap; word-break: break-word; color: #000; background:#fff; }' +
|
|
'pre { margin: 0; padding: 6px; }' +
|
|
'</style></head><bo' + 'dy>' +
|
|
'<pre>' + text.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') + '</pre>' +
|
|
'</bo' + 'dy></ht' + 'ml>';
|
|
w.document.open();
|
|
w.document.write(doc);
|
|
w.document.close();
|
|
w.focus();
|
|
setTimeout(function() {
|
|
try { w.print(); } catch(e) {}
|
|
setTimeout(function() { try { w.close(); } catch(e2) {} }, 500);
|
|
}, 300);
|
|
}
|
|
|
|
function tandaiSelesai(id) {
|
|
if (!confirm('Pesanan meja ini sudah siap saji?')) return;
|
|
|
|
document.getElementById('sync-indicator').style.display = 'block';
|
|
google.script.run.withSuccessHandler(function(res) {
|
|
document.getElementById('sync-indicator').style.display = 'none';
|
|
transaksi = res.transaksi || [];
|
|
renderDapur();
|
|
alert('Pesanan selesai! Silakan diantar ke meja.');
|
|
}).withFailureHandler(function(err) {
|
|
document.getElementById('sync-indicator').style.display = 'none';
|
|
alert('Gagal update: ' + err.message);
|
|
}).updateKitchenStatus(id, 'Ready');
|
|
}
|
|
|
|
// --- Fungsi Chat & Bel ---
|
|
function openChatModal() {
|
|
var body = '<div id="chat-container" style="height: 70vh; display: flex; flex-direction: column;">' +
|
|
'<div id="chat-messages" style="flex-grow: 1; overflow-y: auto; padding: 10px; border: 1px solid #eee; border-radius: 12px; margin-bottom: 10px;"></div>' +
|
|
'<div style="display: flex; gap: 10px;">' +
|
|
'<input id="chat-input" type="text" placeholder="Ketik pesan..." style="flex-grow: 1;">' +
|
|
'<button class="btn-refresh" onclick="sendChat()">KIRIM</button>' +
|
|
'</div>' +
|
|
'</div>';
|
|
openModalCustom(body, 'Chat dengan Kasir');
|
|
renderChat();
|
|
}
|
|
|
|
function renderChat() {
|
|
google.script.run.withSuccessHandler(function(messages) {
|
|
renderChatList(messages);
|
|
}).withFailureHandler(function(err) {
|
|
alert('Gagal memuat chat.\n' + (err && err.message ? err.message : err));
|
|
}).getChatMessages();
|
|
}
|
|
|
|
function renderChatList(messages) {
|
|
var chatBox = document.getElementById('chat-messages');
|
|
if (!chatBox) return;
|
|
chatBox.innerHTML = '';
|
|
messages.forEach(function(msg) {
|
|
var msgDiv = document.createElement('div');
|
|
var isDapur = msg.sender === 'Dapur';
|
|
msgDiv.style.textAlign = isDapur ? 'right' : 'left';
|
|
msgDiv.innerHTML = '<div style="background:' + (isDapur ? '#111' : '#f3f4f6') + '; color:' + (isDapur ? 'white' : '#111') + '; display:inline-block; padding:8px 12px; border-radius:12px; margin-bottom:8px; max-width:80%;">' +
|
|
'<div style="font-weight:bold; font-size:11px; margin-bottom:4px;">' + msg.sender + '</div>' +
|
|
'<div>' + msg.message + '</div>' +
|
|
'<div style="font-size:9px; opacity:0.7; margin-top:4px;">' + new Date(msg.timestamp).toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit' }) + '</div>' +
|
|
'</div>';
|
|
chatBox.appendChild(msgDiv);
|
|
});
|
|
chatBox.scrollTop = chatBox.scrollHeight;
|
|
}
|
|
|
|
function sendChat() {
|
|
var input = document.getElementById('chat-input');
|
|
var message = input.value.trim();
|
|
if (!message) return;
|
|
input.value = '';
|
|
google.script.run.withSuccessHandler(function() {
|
|
renderChat();
|
|
}).withFailureHandler(function(err) {
|
|
alert('Gagal mengirim chat.\n' + (err && err.message ? err.message : err));
|
|
}).sendChatMessage('Dapur', message);
|
|
}
|
|
|
|
function triggerBellDapur() {
|
|
if (!confirm('Panggil Kasir untuk mengambil pesanan?')) return;
|
|
google.script.run.withSuccessHandler(function() {
|
|
alert('Bel Kasir dipicu!');
|
|
}).withFailureHandler(function(err) {
|
|
alert('Gagal memicu bel.\n' + (err && err.message ? err.message : err));
|
|
}).triggerBell('DapurKeKasir');
|
|
}
|
|
|
|
// Modal functions (copy from Index.html)
|
|
function openModalCustom(html, title) {
|
|
document.getElementById('modal').style.display = 'flex';
|
|
document.getElementById('modal-body').innerHTML = html;
|
|
var modalTitle = document.querySelector('#modal .title-sm');
|
|
if (modalTitle) modalTitle.innerText = title || 'Info';
|
|
}
|
|
|
|
function closeModal() {
|
|
document.getElementById('modal').style.display = 'none';
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|