About This Code Showcase
The entire demo lives in a single self-contained demo.html file. No backend, no API key, no build step. The 6-stage conversation is scripted in JavaScript, and the WhatsApp UI is built with plain CSS using the WhatsApp dark theme palette.
Below are the key excerpts: the message rendering helpers, the quote card, and the stage flow that drives the demo.
Core: Message Rendering Helpers
Each conversation turn calls agentReply() or customerMsg(). The agent reply shows a typing indicator before the message lands, just like a real WhatsApp conversation.
const sleep = ms => new Promise(r => setTimeout(r, ms));
function appendBubble(role, text, time, media) {
const box = document.getElementById('msg-box');
const w = document.createElement('div');
w.className = `mw ${role === 'agent' ? 'sent' : 'received'}`;
let mediaHtml = '';
if (media === 'photo') {
mediaHtml = `<div class="media-card">
<div class="media-ico">๐ธ</div>
<div>
<div class="media-n">aircon-indoor.jpg</div>
<div class="media-s">2.4 MB ยท Photo</div>
</div>
</div>`;
}
let quoteHtml = '';
if (media === 'quote') {
quoteHtml = `<div class="quote-card">
<div class="qc-title">Quotation</div>
<div class="qc-row"><span>Service</span><span>Chemical Wash ร 2 units</span></div>
<div class="qc-row"><span>Estimated Time</span><span>1.5 hours</span></div>
<div class="qc-row"><span>Parts</span><span>Cleaning chemicals included</span></div>
<div class="qc-row qc-total"><span>Total</span><span>RM 220</span></div>
</div>`;
}
w.innerHTML = `<div class="bubble">
<div class="b-text">${text}</div>
${mediaHtml}${quoteHtml}
<div class="b-meta">
<span class="b-time">${time}</span>
${role === 'agent' ? '<span class="tick">โโ</span>' : ''}
</div>
</div>`;
box.appendChild(w);
box.scrollTop = box.scrollHeight;
}
async function agentReply(text, time, media) {
showTyping();
await sleep(1800);
hideTyping();
appendBubble('agent', text, time, media);
}
async function customerMsg(text, time, media) {
await sleep(800);
appendBubble('customer', text, time, media);
}
Stage 1 — Customer Inquiry
The customer opens with a question; the AI confirms the service area and immediately starts scoping.
async function startDemo() {
document.getElementById('intro').style.display = 'none';
setStage(1, '๐ฉ Stage 1 โ Customer sends inquiry');
setBtn('Incoming message...', null, true);
updateStats(1, 0, 0, 'โ');
await sleep(1000);
await customerMsg(
'Hi, my bedroom aircon not cold liao. You all do service in Seremban?',
'9:14 AM'
);
await sleep(600);
setStage(1, '๐ค Stage 1 โ AI agent responding to inquiry...');
await agentReply(
'Hi! Yes we cover Seremban and Nilai. Sorry to hear that. ' +
'A few quick questions: how many units are not cold? ' +
'Are they wall-mounted? When was the last service?',
'9:14 AM'
);
updateStats(1, 0, 0, '14s');
setStage(2, 'โ
Stage 1 complete โ Moving to scoping');
setBtn('Customer replies with details...', stage2);
}
Stage 3 — AI Generates the Quote
Once the AI has enough info (unit count, symptoms, last-service date, address), it drops a quote card into the chat with the chemical wash recommendation.
async function stage3() {
setBtn('Processing...', null, true);
setStage(3, 'โ๏ธ Stage 3 โ AI agent providing quote...');
await sleep(500);
appendBanner('โ AI generating quote based on job details โ');
await agentReply(
'Here\'s your quote for the chemical wash:',
'9:17 AM',
'quote'
);
await sleep(300);
await agentReply(
'RM 220 covers both units โ chemical wash, drainage clear, ' +
'gas pressure check, and we\'ll inspect the dripping issue. ' +
'Quote valid 7 days. Want to book a slot?',
'9:17 AM'
);
setStage(4, 'โ
Stage 3 complete โ Quote sent. Waiting for customer...');
setBtn('Customer accepts quote...', stage4);
}
Stage 5 — Confirm + Auto Reminder
After confirming the booking, the demo simulates a same-evening reminder using a banner + agent message.
async function stage5() {
setStage(5, 'โ
Stage 5 โ AI agent confirming booking...');
appendBanner('โ Booking confirmed โ');
await agentReply(
'Booking confirmed! Here\'s your summary:\n\n' +
'โ๏ธ Service: Chemical Wash ร 2 units\n' +
'๐
Date: Tomorrow, 2:00 PM\n' +
'๐ Address: No. 18, Jln Rasah 5, Taman Rasah Jaya, Seremban\n' +
'๐ฐ Price: RM 220 (chemicals included)',
'9:20 AM'
);
updateStats(1, 1, 220, '14s');
await sleep(1500);
appendBanner('โ Tonight 7pm: AI sends automatic reminder โ');
await agentReply(
'Hi Auntie Wong! Just a reminder about your aircon chemical wash ' +
'tomorrow at 2:00 PM. Please make sure both bedroom aircons are ' +
'accessible and switch them off 30 minutes before we arrive.',
'7:00 PM'
);
}