hss-pos / tools /wa_chat.html
sashank1989
feat: add Go mock WhatsApp server and chat simulator for testing
7fa810f
Raw
History Blame Contribute Delete
6.94 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WhatsApp Order Tester</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0b141a; height: 100vh; display: flex; justify-content: center; align-items: center; }
.phone { width: 420px; height: 92vh; background: #0b141a; border-radius: 24px; display: flex; flex-direction: column; overflow: hidden; border: 2px solid #233138; }
.header { background: #1f2c34; padding: 12px 16px; display: flex; align-items: center; gap: 12px; border-bottom: 1px solid #233138; }
.header .avatar { width: 40px; height: 40px; border-radius: 50%; background: #00a884; display: flex; align-items: center; justify-content: center; color: #fff; font-weight: 700; font-size: 16px; flex-shrink: 0; }
.header .info { flex: 1; }
.header .info .name { color: #e9edef; font-size: 16px; font-weight: 600; }
.header .info .status { color: #8696a0; font-size: 12px; }
.header .phone-num { color: #8696a0; font-size: 11px; }
.chat { flex: 1; overflow-y: auto; padding: 12px 16px; background: #0b141a url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23111b21' fill-opacity='0.4'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); display: flex; flex-direction: column; gap: 4px; }
.msg { max-width: 85%; padding: 6px 10px 4px; border-radius: 8px; font-size: 14px; line-height: 1.4; word-wrap: break-word; white-space: pre-wrap; position: relative; }
.msg .time { display: block; text-align: right; font-size: 10px; color: #8696a0; margin-top: 2px; }
.msg.sent { align-self: flex-end; background: #005c4b; color: #e9edef; border-top-right-radius: 2px; }
.msg.recv { align-self: flex-start; background: #1f2c34; color: #e9edef; border-top-left-radius: 2px; }
.msg.system { align-self: center; background: #182229; color: #8696a0; font-size: 12px; padding: 4px 12px; border-radius: 6px; }
.input-bar { background: #1f2c34; padding: 8px 12px; display: flex; gap: 8px; align-items: flex-end; border-top: 1px solid #233138; }
.input-bar input { flex: 1; background: #2a3942; border: none; border-radius: 8px; padding: 10px 14px; color: #e9edef; font-size: 14px; outline: none; }
.input-bar input::placeholder { color: #8696a0; }
.input-bar button { background: #00a884; border: none; border-radius: 50%; width: 42px; height: 42px; cursor: pointer; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.input-bar button:hover { background: #06cf9c; }
.input-bar button:disabled { background: #2a3942; cursor: not-allowed; }
.input-bar button svg { fill: #0b141a; }
.quick-btns { display: flex; gap: 6px; padding: 6px 12px; background: #1f2c34; flex-wrap: wrap; }
.quick-btns button { background: #2a3942; border: 1px solid #3b4d56; color: #e9edef; padding: 5px 12px; border-radius: 16px; font-size: 12px; cursor: pointer; }
.quick-btns button:hover { background: #3b4d56; }
.typing { align-self: flex-start; background: #1f2c34; color: #8696a0; padding: 8px 14px; border-radius: 8px; font-size: 13px; font-style: italic; }
</style>
</head>
<body>
<div class="phone">
<div class="header">
<div class="avatar">R</div>
<div class="info">
<div class="name">My Restaurant</div>
<div class="status" id="conn-status">Connecting...</div>
</div>
<div class="phone-num">+91 98765 43210</div>
</div>
<div class="quick-btns">
<button onclick="send('hi')">hi</button>
<button onclick="send('menu')">menu</button>
<button onclick="send('order')">order</button>
<button onclick="send('done')">done</button>
<button onclick="send('yes')">yes</button>
<button onclick="send('status')">status</button>
<button onclick="send('cancel')">cancel</button>
</div>
<div class="chat" id="chat"></div>
<div class="input-bar">
<input type="text" id="msgInput" placeholder="Type a message..." onkeydown="if(event.key==='Enter')sendMsg()" autofocus />
<button onclick="sendMsg()" id="sendBtn">
<svg width="20" height="20" viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>
</button>
</div>
</div>
<script>
const PHONE = '919876543210';
const WEBHOOK = '/api/v1/webhooks/whatsapp';
const MOCK_API = '/mock-wa';
const chat = document.getElementById('chat');
const input = document.getElementById('msgInput');
const status = document.getElementById('conn-status');
let lastSeq = 0;
let polling = null;
function addMsg(text, type, time) {
const div = document.createElement('div');
div.className = 'msg ' + type;
const t = time || new Date().toLocaleTimeString('en-IN', { hour: '2-digit', minute: '2-digit' });
// Format WhatsApp-style bold (*text*) and newlines
let html = text
.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/\*([^*]+)\*/g, '<strong>$1</strong>');
div.innerHTML = html + '<span class="time">' + t + '</span>';
chat.appendChild(div);
chat.scrollTop = chat.scrollHeight;
}
function addSystem(text) {
const div = document.createElement('div');
div.className = 'msg system';
div.textContent = text;
chat.appendChild(div);
chat.scrollTop = chat.scrollHeight;
}
async function send(text) {
if (!text.trim()) return;
addMsg(text, 'sent');
input.value = '';
const payload = {
entry: [{
changes: [{
value: {
messages: [{
from: PHONE,
type: 'text',
text: { body: text }
}]
}
}]
}]
};
try {
const res = await fetch(WEBHOOK, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!res.ok) addSystem('Webhook error: ' + res.status);
} catch (e) {
addSystem('Failed to send: ' + e.message);
}
}
function sendMsg() {
const text = input.value.trim();
if (text) send(text);
}
async function pollReplies() {
try {
const res = await fetch(MOCK_API + '/messages?since=' + lastSeq);
if (!res.ok) throw new Error(res.status);
const msgs = await res.json();
for (const m of msgs) {
if (m.to === PHONE && m.text) {
addMsg(m.text, 'recv', m.time);
}
lastSeq = m.seq;
}
status.textContent = 'Online';
status.style.color = '#00a884';
} catch (e) {
status.textContent = 'Mock server offline';
status.style.color = '#ea4335';
}
}
// Poll every 500ms
polling = setInterval(pollReplies, 500);
pollReplies();
addSystem('WhatsApp Order Tester');
addSystem('Send "hi" or "menu" to start');
</script>
</body>
</html>