const toggleBtn = document.getElementById("chatbot-toggle-btn"); const closeBtn = document.getElementById("chatbot-close-btn"); const chatWindow = document.getElementById("chatbot-window"); const chatForm = document.getElementById("chatbot-input-form"); const inputField = document.getElementById("chatbot-input-field"); const messagesContainer = document.getElementById("chatbot-messages"); const pulseDot = document.querySelector(".pulse-notification-dot"); // Initialize the new JavaScript intent matching engine using injected PHP data // We add a safety check in case chatbot-engine.js failed to load if (typeof window.PortfolioChatEngine === 'undefined') { console.error("Chat engine not loaded"); } else { const engine = new window.PortfolioChatEngine(window.portfolioData || {}); let isWaiting = false; // Toggle Chat Window if (toggleBtn) { toggleBtn.addEventListener("click", () => { chatWindow.classList.toggle("hidden"); chatWindow.classList.toggle("active"); if (chatWindow.classList.contains("active")) { inputField.focus(); if (pulseDot) pulseDot.style.display = "none"; } }); } if (closeBtn) { closeBtn.addEventListener("click", () => { chatWindow.classList.add("hidden"); chatWindow.classList.remove("active"); }); } // Handle form submit if (chatForm) { chatForm.addEventListener("submit", async (e) => { e.preventDefault(); if (isWaiting) return; const message = inputField.value.trim(); if (!message) return; // Add user message to UI addMessage(message, "user-msg"); inputField.value = ""; isWaiting = true; // Show typing indicator const typingId = showTypingIndicator(); // Simulate network delay for natural feel (600ms - 1200ms) const delay = Math.floor(Math.random() * 600) + 600; setTimeout(() => { // Remove typing indicator removeTypingIndicator(typingId); // Get response from our JS engine instead of API const responseText = engine.match(message); // Display formatted markdown response addMessage(responseText, "bot-msg", true); isWaiting = false; }, delay); }); } // ------------------------------------------------------------- // UI Helpers // ------------------------------------------------------------- function addMessage(text, typeClass, isMarkdown = false) { const msgDiv = document.createElement("div"); msgDiv.className = `chat-message ${typeClass}`; const bubble = document.createElement("div"); bubble.className = "msg-bubble"; if (isMarkdown && typeClass !== "user-msg") { bubble.innerHTML = parseSimpleMarkdown(text); } else { bubble.textContent = text; } msgDiv.appendChild(bubble); messagesContainer.appendChild(msgDiv); scrollToBottom(); } function showTypingIndicator() { const msgDiv = document.createElement("div"); msgDiv.className = "chat-message bot-msg typing-msg"; const id = "typing-" + Date.now(); msgDiv.id = id; const bubble = document.createElement("div"); bubble.className = "msg-bubble typing-bubble"; bubble.innerHTML = ` `; msgDiv.appendChild(bubble); messagesContainer.appendChild(msgDiv); scrollToBottom(); return id; } function removeTypingIndicator(id) { const el = document.getElementById(id); if (el) el.remove(); } function scrollToBottom() { messagesContainer.scrollTo({ top: messagesContainer.scrollHeight, behavior: "smooth" }); } function parseSimpleMarkdown(text) { // Bold: **text** text = text.replace(/\*\*(.*?)\*\*/g, '$1'); // Italic: *text* text = text.replace(/\*(.*?)\*/g, '$1'); // Links: [text](url) text = text.replace(/\[(.*?)\]\((.*?)\)/g, '$1'); // Bullet points: - text or * text // If there are multiple bullets, wrap in '); text = result.join('\n'); } else { // Normal newlines text = text.replace(/\n/g, '
'); } return text; } }