/** * RizQi Stamp — AI Chat Widget (versi pusat) * Host fail ni di SATU tempat sahaja (cth: https://rizqi.com.my/widget.js) * Semua website lain cuma perlu 1 baris untuk panggil fail ni: * * * * Letak baris tu sebelum di setiap website. * Bila-bila anda nak update widget (design, teks, dll), edit SATU fail ni sahaja * — semua website yang panggil fail ni akan terus dapat versi terkini automatik. */ (function () { const WORKER_URL = 'https://chat-bot.rizqistamp.workers.dev'; // <-- Tukar jika Worker URL berubah // ---- Bina HTML widget ---- const wrapper = document.createElement('div'); wrapper.innerHTML = `
Chat dengan kami
`; document.body.appendChild(wrapper); // ---- Logic (sama seperti sebelum ini) ---- const sessionId = localStorage.getItem('rq-session') || 'sess-' + Math.random().toString(36).slice(2); localStorage.setItem('rq-session', sessionId); const bubble = document.getElementById('rq-chat-bubble'); const win = document.getElementById('rq-chat-window'); const preChat = document.getElementById('rq-prechat'); const chatBody = document.getElementById('rq-chat-body'); const nameInput = document.getElementById('rq-name'); const phoneInput = document.getElementById('rq-phone'); const prechatError = document.getElementById('rq-prechat-error'); const startBtn = document.getElementById('rq-prechat-start'); const msgBox = document.getElementById('rq-messages'); const input = document.getElementById('rq-input'); const sendBtn = document.getElementById('rq-send'); bubble.onclick = () => { win.style.display = win.style.display === 'flex' ? 'none' : 'flex'; }; function addMsg(text, who) { const div = document.createElement('div'); div.textContent = text; div.style.cssText = who === 'user' ? 'align-self:flex-end;background:#1E293B;color:#fff;padding:8px 10px;border-radius:10px 10px 2px 10px;max-width:80%;' : 'align-self:flex-start;background:#fff;border:1px solid #DCD3BC;padding:8px 10px;border-radius:10px 10px 10px 2px;max-width:80%;'; msgBox.appendChild(div); msgBox.scrollTop = msgBox.scrollHeight; } function isValidPhone(v) { const digits = v.replace(/[^0-9]/g, ''); return digits.length >= 9 && digits.length <= 13; } function startChat(customerName, customerPhone) { localStorage.setItem('rq-name', customerName); localStorage.setItem('rq-phone', customerPhone); preChat.style.display = 'none'; chatBody.style.display = 'flex'; addMsg('Hai ' + customerName + '! Saya AI RizQi Stamp. Ada apa yang boleh saya bantu?', 'bot'); } startBtn.onclick = () => { const nm = nameInput.value.trim(); const ph = phoneInput.value.trim(); if (!nm || !isValidPhone(ph)) { prechatError.style.display = 'block'; return; } prechatError.style.display = 'none'; startChat(nm, ph); }; async function send() { const text = input.value.trim(); if (!text) return; addMsg(text, 'user'); input.value = ''; try { const res = await fetch(WORKER_URL + '/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sessionId, message: text, customerName: localStorage.getItem('rq-name') || '', customerPhone: localStorage.getItem('rq-phone') || '' }) }); const data = await res.json(); if (data.reply) addMsg(data.reply, 'bot'); if (data.handedOff) addMsg('Baik, saya sambungkan anda dengan staff kami sebentar ya.', 'bot'); } catch (e) { addMsg('Maaf, ralat sambungan. Sila cuba lagi.', 'bot'); } } sendBtn.onclick = send; input.addEventListener('keydown', e => { if (e.key === 'Enter') send(); }); setInterval(async () => { try { const res = await fetch(WORKER_URL + '/api/poll?session=' + sessionId); const data = await res.json(); (data.replies || []).forEach(r => addMsg(r, 'bot')); } catch (e) {} }, 4000); const savedName = localStorage.getItem('rq-name'); const savedPhone = localStorage.getItem('rq-phone'); if (savedName && savedPhone) { nameInput.value = savedName; phoneInput.value = savedPhone; startChat(savedName, savedPhone); } })();