const chatMessages = document.getElementById('chat-messages'); const chatInput = document.getElementById('chat-input'); const sendButton = document.getElementById('send-button'); const errorMessage = document.getElementById('error-message'); const headerTitle = document.getElementById('chat-header-title'); const headerSubtitle = document.getElementById('chat-header-subtitle'); const closeButton = document.getElementById('close-button'); const loadingPlaceholder = document.getElementById('loading-placeholder'); const suggestionsContainer = document.getElementById('suggestions-container'); let API_WEBHOOK_URL = 'https://agent.vynex.org/webhook/2174d0c4-093c-4835-9f89-825a4a345319'; let INITIAL_MESSAGE = 'Hello! How can I help you?'; let HEADER_TITLE = 'Chat Assistant'; let SUBTITLE = 'Brilliant Directories AI Assistant'; let USER_ID = { staticId: 'unknown-widget-user' }; let ACCENT_COLOR = '#1a73e8'; let USER_MSG_BG = '#e1f5fe'; let BOT_MSG_BG = '#f1f1f1'; let API_REQUEST_MESSAGE_KEY = 'message'; let isLoading = false; let loadingIndicatorElement = null; function getQueryParam(param) { const urlParams = new URLSearchParams(window.location.search); const value = urlParams.get(param); return value ? decodeURIComponent(value) : null; } function applyConfiguration() { const configWebhookUrl = getQueryParam('webhookUrl'); const configInitialMessage = getQueryParam('initialMessage'); const configTitle = getQueryParam('title'); const configSubtitle = getQueryParam('subtitle'); const configUserId = getQueryParam('userId'); const configAccent = getQueryParam('accentColor'); const configAccentSecondary = getQueryParam('accentColorSecondary'); const configUserBg = getQueryParam('userMsgBg'); const configAgentBg = getQueryParam('agentMsgBg'); if (configWebhookUrl) API_WEBHOOK_URL = configWebhookUrl; if (configInitialMessage) INITIAL_MESSAGE = configInitialMessage; if (configTitle) HEADER_TITLE = configTitle; if (configSubtitle) SUBTITLE = configSubtitle; if (configAccent) document.documentElement.style.setProperty('--accent-color', configAccent); if (configAccentSecondary) document.documentElement.style.setProperty('--accent-color-secondary', configAccentSecondary); if (configUserBg) document.documentElement.style.setProperty('--user-msg-bg', configUserBg); if (configAgentBg) document.documentElement.style.setProperty('--agent-msg-bg', configAgentBg); if (configUserId) { try { USER_ID = JSON.parse(configUserId); if (typeof USER_ID !== 'object' || USER_ID === null) { console.warn("Received userId parameter is not a valid JSON object, using default."); USER_ID = { staticId: 'unknown-widget-user' }; } } catch (e) { console.error("Failed to parse userId parameter, using default.", e); USER_ID = { staticId: 'error-parsing-user-id' }; } } headerTitle.textContent = HEADER_TITLE; headerSubtitle.textContent = SUBTITLE; } function displayMessage(text, sender) { hideLoading(); const messageDiv = document.createElement('div'); messageDiv.classList.add('message', `${sender}-message`); const searchResultsDiv = document.querySelector(".grid-container"); if (sender === 'agent') { try { marked.setOptions({ breaks: true, gfm: true }); const messageText = typeof text === 'object' ? text.output : text; const rawHtml = marked.parse(messageText || ""); const sanitizedHtml = DOMPurify.sanitize(rawHtml); messageDiv.innerHTML = sanitizedHtml; if (typeof text === 'object' && text !== null) { if(text.posts && Array.isArray(text.posts)|| text.members && Array.isArray(text.members) ) { searchResultsDiv.innerHTML = ""; document.querySelectorAll( ".member-search-result-count-container, .member_results_header, .member-search-result-filters, .member_results_header ~ hr, .member_results_header ~ br, .member-pagination-block, .module" ).forEach(el => el.style.display = "none"); } if (text.members && Array.isArray(text.members)) { const membersContainer = document.createElement('div'); membersContainer.classList.add('chat-widget-container'); const membersList = document.createElement('ul'); membersList.classList.add('chat-widget-list'); text.members.forEach(member => { const memberItem = document.createElement('li'); memberItem.classList.add('chat-widget-item'); console.log(member); const profilePhoto = member.photo ? `https://www.talkinghealthtech.com/logos/profile/${member.photo}` : 'https://placehold.co/36x36/6a82fb/ffffff?text=' + member.name.charAt(0); const location = [member.city, member.state_ln] .filter(Boolean) .join(', '); const services = member.services.slice(0, 3).join(', '); memberItem.innerHTML = `
${member.name}
${member.name} ${Number(member.verified) > 0 ? '' : ''} ${member.avg_rating ? ` ${member.avg_rating} ` : ''}
${location}
${Array.isArray(member.services) && member.services.length ? member.services.slice(0, 3).map(service => `${service}` ).join('') : 'No services' }
${member.about_me}
`; membersList.appendChild(memberItem); }); membersContainer.appendChild(membersList); searchResultsDiv.appendChild(membersContainer); } if (text.posts && Array.isArray(text.posts)) { const postsContainer = document.createElement('div'); postsContainer.classList.add('chat-widget-container'); const postsList = document.createElement('ul'); postsList.classList.add('chat-widget-list'); text.posts.forEach(post => { const postItem = document.createElement('li'); postItem.classList.add('chat-widget-item'); const thumbnail = post.image ? `https://www.talkinghealthtech.com${post.image}` : `https://placehold.co/70x50/17a2b8/ffffff?text=${encodeURIComponent(post.category || 'Post')}`; const location = post.location || 'Online'; let dateStr = ''; if (post.post_live_date) { try { const date = new Date(post.post_live_date); if (!isNaN(date.getTime())) { dateStr = date.toLocaleString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); } else { dateStr = post.post_live_date; } } catch (e) { dateStr = post.post_live_date; } } const tags = post.post_tags ? post.post_tags.split(',').map(tag => tag.trim()) : []; postItem.innerHTML = `
Post Thumbnail
By ${post.author || 'Unknown'}
${post.title || ''}
${post.category || ''}
${location}
${post.description ? post.description.substring(0, 120) + (post.description.length > 120 ? '...' : '') : ''}
${tags.length > 0 ? `
${tags.map(tag => `${tag}`).join('')}
` : ''}
Details
${dateStr}
`; postsList.appendChild(postItem); }); postsContainer.appendChild(postsList); searchResultsDiv.appendChild(postsContainer); } } } catch (error) { console.error("Error processing agent message:", error); messageDiv.textContent = typeof text === 'object' ? text.output : text; } } else { messageDiv.textContent = text; } chatMessages.appendChild(messageDiv); scrollToBottom(); } function scrollToBottom() { chatMessages.scrollTop = chatMessages.scrollHeight; } function showLoading() { if (isLoading) return; isLoading = true; updateSendButtonState(); if (!loadingIndicatorElement) { loadingIndicatorElement = document.createElement('div'); loadingIndicatorElement.classList.add('loading-indicator'); loadingIndicatorElement.innerHTML = ``; } chatMessages.appendChild(loadingIndicatorElement); scrollToBottom(); } function hideLoading() { if (!isLoading) return; isLoading = false; if (loadingIndicatorElement && loadingIndicatorElement.parentNode) { loadingIndicatorElement.parentNode.removeChild(loadingIndicatorElement); } updateSendButtonState(); } function showAgentError(message) { if (message) { errorMessage.textContent = message; errorMessage.style.display = 'block'; } else { errorMessage.style.display = 'none'; } scrollToBottom(); } function autoResizeTextarea() { const textarea = chatInput; textarea.style.height = '48px'; const newHeight = Math.min(Math.max(textarea.scrollHeight, 48), 200); textarea.style.height = newHeight + 'px'; } function updateSendButtonState() { const hasText = chatInput.value.trim().length > 0; sendButton.disabled = !hasText || isLoading; } chatInput.addEventListener('input', () => { autoResizeTextarea(); updateSendButtonState(); }); chatInput.addEventListener('keydown', (event) => { if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); if (!sendButton.disabled) { sendMessageToApi(); } } }); sendButton.addEventListener('click', () => { if (!sendButton.disabled) { sendMessageToApi(); } }); function handleSuggestionClick(event) { if (event.target.classList.contains('suggestion-bubble')) { const suggestionText = event.target.textContent; chatInput.value = suggestionText; sendMessageToApi(); suggestionsContainer.style.display = 'none'; } } suggestionsContainer.addEventListener('click', handleSuggestionClick); const originalSendMessage = sendMessageToApi; sendMessageToApi = function() { if (chatInput.value.trim() === '') return; originalSendMessage(); suggestionsContainer.style.display = 'none'; chatInput.style.height = '48px'; chatInput.value = ''; updateSendButtonState(); }; document.addEventListener('DOMContentLoaded', () => { applyConfiguration(); if (INITIAL_MESSAGE) { displayMessage(INITIAL_MESSAGE, 'agent'); } scrollToBottom(); updateSendButtonState(); chatInput.focus(); suggestionsContainer.style.display = 'flex'; }); chatInput.addEventListener('input', () => { if (chatInput.value === '') { suggestionsContainer.style.display = 'flex'; } }); async function sendMessageToApi() { const userMessage = chatInput.value.trim(); if (!userMessage || isLoading) return; displayMessage(userMessage, 'user'); chatInput.value = ''; updateSendButtonState(); showAgentError(null); showLoading(); try { const requestData = { [API_REQUEST_MESSAGE_KEY]: userMessage, user: USER_ID }; const response = await fetch(API_WEBHOOK_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }); if (!response.ok) { let errorDetails = `HTTP error! Status: ${response.status}`; try { const errorData = await response.json(); errorDetails += ` - ${errorData.message || JSON.stringify(errorData)}`; } catch (e) { /* Ignore */ } throw new Error(errorDetails); } const data = await response.json(); const API_RESPONSE_MESSAGE_KEY = 'output'; const agentReply = data[API_RESPONSE_MESSAGE_KEY]; if (typeof agentReply === 'string' && agentReply.length > 0) { const messageData = { output: agentReply, members: data.members, posts: data.posts }; displayMessage(messageData, 'agent'); } else if (agentReply) { displayMessage(String(agentReply), 'agent'); console.warn('Received agent reply, but not a non-empty string.', {response: data}); } else { console.warn('Received response, but expected key missing/empty.', {key: API_RESPONSE_MESSAGE_KEY, response: data}); displayMessage("Sorry, I didn't get a valid response structure.", 'agent'); } } catch (error) { console.error('Error sending/receiving message:', error); hideLoading(); showAgentError(`Error: ${error.message || 'Could not reach assistant.'}`); } finally { chatInput.focus(); updateSendButtonState(); } } sendButton.addEventListener('click', sendMessageToApi); chatInput.addEventListener('keydown', (event) => { if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); if (!sendButton.disabled) { sendMessageToApi(); } } }); closeButton.addEventListener('click', () => { window.parent.postMessage('closeChatWidget', '*'); });