// PayParse — minimal vanilla-JS chat client for the /api/chat endpoint. const chatWindow = document.getElementById("chatWindow"); const composerForm = document.getElementById("composerForm"); const messageInput = document.getElementById("messageInput"); const sendButton = document.getElementById("sendButton"); const resetButton = document.getElementById("resetButton"); const engineBadge = document.getElementById("engineBadge"); const quickReplies = document.getElementById("quickReplies"); let sessionId = crypto.randomUUID(); function scrollToBottom() { chatWindow.scrollTop = chatWindow.scrollHeight; } function appendMessage(text, sender) { const row = document.createElement("div"); row.className = `msg msg-${sender}`; const bubble = document.createElement("div"); bubble.className = "bubble"; bubble.textContent = text; row.appendChild(bubble); chatWindow.appendChild(row); scrollToBottom(); return row; } function appendPayload(payload) { const row = document.createElement("div"); row.className = "msg msg-bot"; const bubble = document.createElement("div"); bubble.className = "bubble payload"; bubble.textContent = JSON.stringify(payload, null, 2); row.appendChild(bubble); chatWindow.appendChild(row); scrollToBottom(); } function showTyping() { const row = document.createElement("div"); row.className = "msg msg-bot typing"; row.id = "typingIndicator"; row.innerHTML = `
`; chatWindow.appendChild(row); scrollToBottom(); } function hideTyping() { const el = document.getElementById("typingIndicator"); if (el) el.remove(); } async function loadHealth() { try { const res = await fetch("/health"); const data = await res.json(); engineBadge.textContent = data.offline_mode ? "Mode: Offline (Mock)" : "Mode: Gemini Live"; } catch { engineBadge.textContent = "Tidak terhubung"; } } async function sendMessage(text) { appendMessage(text, "user"); messageInput.value = ""; sendButton.disabled = true; showTyping(); try { const res = await fetch("/api/chat", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ session_id: sessionId, message: text }), }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); hideTyping(); appendMessage(data.reply, "bot"); if (data.is_complete && data.payload) { appendPayload(data.payload); // Transaction finished server-side; start a fresh session for the next one. sessionId = crypto.randomUUID(); } } catch (err) { hideTyping(); appendMessage("Maaf, terjadi kendala koneksi ke server. Coba lagi ya.", "bot"); console.error(err); } finally { sendButton.disabled = false; messageInput.focus(); } } composerForm.addEventListener("submit", (e) => { e.preventDefault(); const text = messageInput.value.trim(); if (!text) return; sendMessage(text); }); quickReplies.addEventListener("click", (e) => { const chip = e.target.closest(".chip"); if (!chip) return; sendMessage(chip.dataset.text); }); resetButton.addEventListener("click", async () => { try { await fetch(`/api/session/${sessionId}`, { method: "DELETE" }); } catch { /* session may already be gone; ignore */ } sessionId = crypto.randomUUID(); chatWindow.innerHTML = ""; appendMessage( 'Oke, mulai dari awal. Mau dibantu transfer, beli pulsa, atau bayar listrik?', "bot" ); }); loadHealth(); messageInput.focus();