/** * Kayra AI Chatbot Widget * Version: 1.0.0 */ (function() { // Widget yapılandırmasını al const scriptTag = document.currentScript; const widgetId = scriptTag.getAttribute('data-widget-id'); const isPreview = scriptTag.getAttribute('data-preview') === 'true'; if (!widgetId) { console.error('Kayra Chatbot: Widget ID bulunamadı!'); return; } // Domain kontrolü fonksiyonu function isDomainAllowed(allowedDomains) { // Eğer önizleme modundaysa, domain kontrolünü atla if (isPreview) { return true; } // Eğer allowed_domains boş veya null ise, tüm domainlere izin ver if (!allowedDomains) { return true; } // Mevcut domain adını al const currentDomain = window.location.hostname; // Allowed domains string'ini noktalı virgülle ayırarak bir diziye dönüştür const domainList = allowedDomains.split(';').map(domain => domain.trim().toLowerCase()); // Mevcut domain'in izin verilen domainler listesinde olup olmadığını kontrol et return domainList.some(domain => { // Eğer domain http:// veya https:// ile başlıyorsa, sadece hostname kısmını al if (domain.startsWith('http://')) { domain = domain.substring(7); } else if (domain.startsWith('https://')) { domain = domain.substring(8); } // "www." ön ekini kaldır if (domain.startsWith('www.')) { domain = domain.substring(4); } // Tam domain eşleşmesi kontrolü if (domain === currentDomain) { return true; } // Alt domain kontrolü (örn: test.example.com, example.com'a izin veriliyorsa) if (currentDomain.endsWith('.' + domain)) { return true; } // Domain parçalarını nokta ile ayırarak daha esnek eşleştirme // Örneğin hairaestheticclinic.co.uk veya hairaestheticclinic.com.tr gibi const currentParts = currentDomain.split('.'); const allowedParts = domain.split('.'); // Özellikle co.uk, com.tr gibi uzantılar için özel kontrol // domain son kısmı en az 2 parçadan oluşuyorsa (.co.uk, .com.tr gibi) if (allowedParts.length >= 2) { // Domain adı kısmını al (örn: hairaestheticclinic) const baseDomainName = allowedParts[0]; // Uzantı kısmını al (örn: co.uk, com.tr) const domainExtension = allowedParts.slice(1).join('.'); // Mevcut domainin, izin verilen base adı ve uzantı ile eşleşip eşleşmediğini kontrol et if (currentParts.length >= allowedParts.length) { const currentBaseName = currentParts[0]; const currentExtension = currentParts.slice(1).join('.'); if (currentBaseName === baseDomainName && currentExtension === domainExtension) { return true; } } } return false; }); } // Dil ayarını HTML lang özelliğinden al const htmlLang = document.documentElement.lang.toLowerCase(); // TR için tr, EN için en, diğer tüm diller için en kullan const widgetLang = htmlLang === 'tr' ? 'tr' : 'en'; // Çeviriler const translations = { tr: { notFound: 'Widget ID bulunamadı!', chatToggle: 'Chat Aç/Kapat', chatClose: 'Sohbeti Küçült', resetChat: 'Konuşmayı Sıfırla', resetChatAll: 'Tümünü Sıfırla', you: 'Siz', typingPlaceholder: 'Mesajınızı yazın...', welcomeDefault: 'Merhaba! Size nasıl yardımcı olabilirim?', resetConfirm: 'Tüm görüşme geçmişiniz, KVKK izinleriniz ve bilgileriniz silinecek. Emin misiniz?', errorMessage: 'Üzgünüm, bir hata oluştu. Lütfen daha sonra tekrar deneyin.', noResponseError: 'Üzgünüm, yanıt veremiyorum.', formTitle: 'Lütfen aşağıdaki bilgileri doldurun', fullName: 'Ad Soyad', phoneNumber: 'Telefon Numarası', email: 'E-posta Adresi', otherInfo: 'Diğer Bilgi', requiredFields: 'Lütfen zorunlu alanları doldurunuz.', fillLater: 'Sonra Doldur', continue: 'Devam Et', yes: 'Evet, Onaylıyorum', no: 'Hayır, Onaylamıyorum', consentDefault: 'Konuşmaya başlamadan önce, lütfen veri gizliliği (KVKK) bildirimini onaylayın. Onaylıyor musunuz?' }, en: { notFound: 'Widget ID not found!', chatToggle: 'Toggle Chat', chatClose: 'Minimize Chat', resetChat: 'Reset Conversation', resetChatAll: 'Reset All', you: 'You', typingPlaceholder: 'Type your message...', welcomeDefault: 'Hello! How can I help you?', resetConfirm: 'All your conversation history, privacy consents and information will be deleted. Are you sure?', errorMessage: 'Sorry, an error occurred. Please try again later.', noResponseError: 'Sorry, I cannot respond.', formTitle: 'Please fill in the information below', fullName: 'Full Name', phoneNumber: 'Phone Number', email: 'Email Address', otherInfo: 'Other Information', requiredFields: 'Please fill in the required fields.', fillLater: 'Fill Later', continue: 'Continue', yes: 'Yes, I Agree', no: 'No, I Disagree', consentDefault: 'Before starting the conversation, please approve the data privacy notice. Do you agree?' } }; // Çeviri fonksiyonu function t(key) { return translations[widgetLang][key] || translations['tr'][key] || key; } // Temel URL'yi al const baseUrl = scriptTag.src.split('/api/')[0]; let widgetConfig = null; let isWidgetOpen = false; let messageHistory = []; // LocalStorage anahtar isimleri const STORAGE_KEY_HISTORY = `kayra_chat_history_${widgetId}`; const STORAGE_KEY_OPEN = `kayra_chat_open_${widgetId}_v2`; const STORAGE_KEY_LAST_ACTIVITY = `kayra_chat_last_activity_${widgetId}`; const STORAGE_KEY_LAST_EXIT = `kayra_chat_last_exit_${widgetId}`; const STORAGE_KEY_CONSENT = `kayra_chat_consent_${widgetId}`; const STORAGE_KEY_USER_INFO = `kayra_chat_user_info_${widgetId}`; const CHAT_TIMEOUT_MINUTES = 10; // 10 dakika sonra sohbeti temizle // LocalStorage'dan sohbet geçmişini yükle function loadChatHistory() { try { // Sayfa yeniden giriş kontrolü const pageReentryTimedOut = checkPageReentry(); if (!pageReentryTimedOut) { // Sayfa kapama zaman aşımı yoksa geçmişi yükle const savedHistory = localStorage.getItem(STORAGE_KEY_HISTORY); if (savedHistory) { messageHistory = JSON.parse(savedHistory); } // NOT: Widget açık/kapalı durumu artık fetchWidgetConfig içinde kontrol ediliyor // Bu şekilde kullanıcı tercihi ile is_open değeri arasındaki öncelik doğru şekilde yönetiliyor } // Son aktivite zamanını güncelle updateLastActivity(); } catch (error) { console.error('Sohbet geçmişi yüklenirken hata:', error); } } // Sohbet geçmişini LocalStorage'a kaydet function saveChatHistory() { try { // Mesaj geçmişini belirli bir uzunlukta tut (son 50 mesaj) if (messageHistory.length > 50) { messageHistory = messageHistory.slice(-50); } localStorage.setItem(STORAGE_KEY_HISTORY, JSON.stringify(messageHistory)); // Eğer mesaj varsa sunucuya da kaydet if (messageHistory.length > 0) { saveConversationToServer(); } } catch (error) { console.error('Sohbet geçmişi kaydedilirken hata:', error); } } // Sohbeti sunucuya kaydet async function saveConversationToServer() { try { // Konuşma tamamlandıysa (sıfırlandıysa) yeni bir session ID oluştur let sessionId = localStorage.getItem(`kayra_chat_session_${widgetId}`); const isResetChat = localStorage.getItem(`kayra_chat_reset_${widgetId}`) === 'true'; const isCompletedChat = localStorage.getItem(`kayra_chat_completed_${widgetId}`) === 'true'; // Eğer sohbet sıfırlanmışsa veya sessionId yoksa yeni bir session ID oluştur if (isResetChat || !sessionId) { // Benzersiz bir session ID oluştur sessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substring(2, 15); localStorage.setItem(`kayra_chat_session_${widgetId}`, sessionId); // Sıfırlama durumunu temizle localStorage.removeItem(`kayra_chat_reset_${widgetId}`); } // Kullanıcı bilgilerini al const userInfo = getUserInfo() || {}; // API isteği gönder const response = await fetch(`${baseUrl}/api/chatbot-widgets/${widgetId}/save-conversation`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: sessionId, messages: messageHistory, user_info: userInfo, is_completed: isCompletedChat }) }); const data = await response.json(); if (!data.success) { console.error('Sohbet kaydedilemedi:', data.message); } else { console.debug('Sohbet başarıyla kaydedildi. Conversation ID:', data.conversation_id); // Eğer konuşma tamamlandıysa, işlem tamamlandı flagini temizleyelim if (isCompletedChat) { localStorage.removeItem(`kayra_chat_completed_${widgetId}`); // Konuşma tamamlandıysa ve isResetChat true değilse // yeni bir session ID oluşturmamız gerekiyor // böylece bir sonraki konuşma yeni bir kayıt olarak başlayacak if (!isResetChat) { // Benzersiz bir session ID oluştur const newSessionId = 'session_' + Date.now() + '_' + Math.random().toString(36).substring(2, 15); localStorage.setItem(`kayra_chat_session_${widgetId}`, newSessionId); } } } } catch (error) { console.error('Sohbet verileri sunucuya kaydedilirken hata:', error); } } // Widget açık/kapalı durumunu kaydet function saveWidgetState(isOpen) { try { console.log(`Widget durumu kaydediliyor: ${isOpen ? 'AÇIK' : 'KAPALI'}`); localStorage.setItem(STORAGE_KEY_OPEN, isOpen.toString()); } catch (error) { console.error('Widget durumu kaydedilirken hata:', error); } } // Widget CSS yükle function loadStyles() { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = `${baseUrl}/css/chatbot-widget.css`; document.head.appendChild(link); } // Widget yapılandırmasını al async function fetchWidgetConfig() { try { // URL'yi routes/api.php'deki tanımla eşleştiriyoruz const response = await fetch(`${baseUrl}/api/chatbot-widgets/${widgetId}/config`); const data = await response.json(); if (data.success) { widgetConfig = data.widget; console.debug('Widget config loaded:', widgetConfig); // Domain kontrolü yap if (!isDomainAllowed(widgetConfig.allowed_domains)) { console.error('Kayra Chatbot: Bu domain için widget kullanımına izin verilmiyor.'); return null; } // DEBUG: is_open değeri çıktısı console.log('API widget is_open değeri:', widgetConfig.is_open); // LocalStorage'da kullanıcı tercihi var mı kontrol et const hasStoredPreference = localStorage.getItem(STORAGE_KEY_OPEN) !== null; if (hasStoredPreference) { // Kullanıcı daha önce bir tercih yapmış, localStorage'daki değeri kullan const userPreference = localStorage.getItem(STORAGE_KEY_OPEN) === 'true'; console.log('Kullanıcı tercihi bulundu. Widget ' + (userPreference ? 'AÇIK' : 'KAPALI') + ' olacak.'); isWidgetOpen = userPreference; } else { // Kullanıcı henüz bir tercih yapmamış, API'den gelen is_open değerini kullan console.log('Kullanıcı tercihi bulunamadı. API değerine göre widget ' + (widgetConfig.is_open ? 'AÇIK' : 'KAPALI') + ' olacak.'); isWidgetOpen = widgetConfig.is_open; // İlk tercihi de localStorage'a kaydet (ilk ziyaret için) saveWidgetState(isWidgetOpen); } // İlgili mesajları çeviriler için ayarla if (widgetLang === 'tr') { widgetConfig.welcome_message = widgetConfig.welcome_message_tr || widgetConfig.welcome_message; widgetConfig.consent_message = widgetConfig.consent_message_tr || widgetConfig.consent_message; if (widgetConfig.bot_role === 'custom') { widgetConfig.custom_instructions = widgetConfig.custom_instructions_tr || widgetConfig.custom_instructions; } if (widgetConfig.prompt_template) { widgetConfig.prompt_template = widgetConfig.prompt_template_tr || widgetConfig.prompt_template; } } else { widgetConfig.welcome_message = widgetConfig.welcome_message_en || widgetConfig.welcome_message; widgetConfig.consent_message = widgetConfig.consent_message_en || widgetConfig.consent_message; if (widgetConfig.bot_role === 'custom') { widgetConfig.custom_instructions = widgetConfig.custom_instructions_en || widgetConfig.custom_instructions; } if (widgetConfig.prompt_template) { widgetConfig.prompt_template = widgetConfig.prompt_template_en || widgetConfig.prompt_template; } } // Önizleme modunda değilse görüntüleme sayısını artır if (!isPreview) { // Widget görüntüleme sayısını artır fetch(`${baseUrl}/api/chatbot-widgets/${widgetId}/view`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }).catch(err => console.error('View count error:', err)); } else { console.log('Önizleme modu aktif: Görüntülenme sayısı artırılmadı'); } // Widget'ı görüntüle renderWidget(); return widgetConfig; } else { console.error('Failed to load widget config'); return null; } } catch (error) { console.error('Error fetching widget config:', error); return null; } } // Widget HTML yapısını oluştur function renderWidget() { if (!widgetConfig) return; // Temel widget container const widgetContainer = document.createElement('div'); widgetContainer.id = 'kayra-chatbot-widget'; widgetContainer.className = `kayra-widget kayra-position-${widgetConfig.widget_position || 'bottom-right'}`; document.body.appendChild(widgetContainer); // Chat toggle button const toggleButton = document.createElement('button'); toggleButton.className = `kayra-chat-toggle kayra-theme-${widgetConfig.theme_color || 'primary'}`; toggleButton.innerHTML = ` `; toggleButton.setAttribute('aria-label', t('chatToggle')); widgetContainer.appendChild(toggleButton); // Widget tıklandığında temizlenmişse tekrar izin ve form isteme adımlarına dönmesi için toggleButton.addEventListener('click', function() { if (!hasUserConsent() && widgetConfig.require_consent) { // KVKK onayı alınmadıysa veya temizlendiyse const chatContainer = widgetContainer.querySelector('.kayra-chat-container'); if (chatContainer) { // Mevcut içeriği temizle while (chatContainer.firstChild) { chatContainer.removeChild(chatContainer.firstChild); } // Chat header const chatHeader = document.createElement('div'); chatHeader.className = `kayra-chat-header kayra-theme-${widgetConfig.theme_color || 'primary'}`; chatHeader.innerHTML = `
${widgetConfig.name || 'Chat Bot'}
`; chatContainer.appendChild(chatHeader); // KVKK formunu göster renderConsentForm(chatContainer); } } else if (widgetConfig.require_user_info && !hasUserInfo()) { // KVKK onayı var ama kullanıcı bilgileri yoksa const chatContainer = widgetContainer.querySelector('.kayra-chat-container'); if (chatContainer) { // Mevcut içeriği temizle while (chatContainer.firstChild) { chatContainer.removeChild(chatContainer.firstChild); } // Chat header const chatHeader = document.createElement('div'); chatHeader.className = `kayra-chat-header kayra-theme-${widgetConfig.theme_color || 'primary'}`; chatHeader.innerHTML = `
${widgetConfig.name || 'Chat Bot'}
`; chatContainer.appendChild(chatHeader); // Kullanıcı bilgi formunu göster renderUserInfoForm(chatContainer); } } }); // Chat container oluştur (başlangıçta gizli) const chatContainer = document.createElement('div'); chatContainer.className = 'kayra-chat-container'; // Widget'ın durumunu belirle ve ayarla // Not: Bu satır değiştirildi, isWidgetOpen değişkeni fetchWidgetConfig içinde ayarlanıyor // O yüzden burada doğru değeri doğrudan kullanıyoruz console.log('Widget rendering with isWidgetOpen:', isWidgetOpen); chatContainer.style.display = isWidgetOpen ? 'flex' : 'none'; toggleButton.style.display = isWidgetOpen ? 'none' : 'flex'; widgetContainer.appendChild(chatContainer); // Chat header const chatHeader = document.createElement('div'); chatHeader.className = `kayra-chat-header kayra-theme-${widgetConfig.theme_color || 'primary'}`; chatHeader.innerHTML = `
${widgetConfig.name || 'Chat Bot'}
`; chatContainer.appendChild(chatHeader); // Koşullu form veya sohbet arayüzü gösterimi if (widgetConfig.require_consent && !hasUserConsent()) { renderConsentForm(chatContainer); } else if (widgetConfig.require_user_info && !hasUserInfo()) { renderUserInfoForm(chatContainer); } else { renderChatInterface(chatContainer); } // Event listeners setupAllEventListeners(); } // Chat arayüzünü oluştur function renderChatInterface(chatContainer) { // Kullanıcı adını al (varsa) const userInfo = getUserInfo(); const userName = (userInfo && userInfo.name) ? userInfo.name : t('you'); // Chat messages const chatMessages = document.createElement('div'); chatMessages.className = 'kayra-chat-messages'; chatContainer.appendChild(chatMessages); // Kaydedilmiş mesajları göster if (messageHistory.length > 0) { messageHistory.forEach(msg => { const messageElement = document.createElement('div'); messageElement.className = `kayra-message kayra-${msg.sender}-message`; if (msg.sender === 'bot') { messageElement.innerHTML = `
${widgetConfig.bot_name || 'Chat Bot'}
${msg.message}
`; } else { messageElement.innerHTML = `
${userName}
${msg.message}
`; } chatMessages.appendChild(messageElement); }); // Scroll en alta setTimeout(() => { chatMessages.scrollTop = chatMessages.scrollHeight; }, 100); } else { // Eğer mesaj geçmişi yoksa hoşgeldin mesajı göster const welcomeMessage = document.createElement('div'); welcomeMessage.className = 'kayra-message kayra-bot-message'; // Dil'e uygun hoşgeldin mesajını seç let welcomeText = t('welcomeDefault'); if (widgetLang === 'tr' && widgetConfig.welcome_message_tr) { welcomeText = widgetConfig.welcome_message_tr; } else if (widgetLang === 'en' && widgetConfig.welcome_message_en) { welcomeText = widgetConfig.welcome_message_en; } else if (widgetConfig.welcome_message) { // Eski versiyon uyumluluğu için welcomeText = widgetConfig.welcome_message; } welcomeMessage.innerHTML = `
${widgetConfig.bot_name || 'Chat Bot'}
${welcomeText}
`; chatMessages.appendChild(welcomeMessage); } // Chat input const chatInputContainer = document.createElement('div'); chatInputContainer.className = 'kayra-chat-input-container'; chatInputContainer.innerHTML = ` `; chatContainer.appendChild(chatInputContainer); } // KVKK Onay formunu oluştur function renderConsentForm(chatContainer) { if (!widgetConfig.require_consent) return false; // Daha önce onay verilmiş mi kontrol et if (hasUserConsent()) return false; // Onay formu container const consentForm = document.createElement('div'); consentForm.className = 'kayra-consent-form'; // Dil'e uygun onay mesajını seç let consentText = t('consentDefault'); if (widgetLang === 'tr' && widgetConfig.consent_message_tr) { consentText = widgetConfig.consent_message_tr; } else if (widgetLang === 'en' && widgetConfig.consent_message_en) { consentText = widgetConfig.consent_message_en; } else if (widgetConfig.consent_message) { // Eski versiyon uyumluluğu için consentText = widgetConfig.consent_message; } // Form HTML'i consentForm.innerHTML = ` `; // Onay formu event listener'larını ekle setTimeout(() => { const yesButton = document.getElementById('kayra-consent-yes'); const noButton = document.getElementById('kayra-consent-no'); if (yesButton) { yesButton.addEventListener('click', () => { saveUserConsent(true); chatContainer.removeChild(consentForm); // Kullanıcı bilgileri formu gerekiyorsa göster if (widgetConfig.require_user_info) { renderUserInfoForm(chatContainer); } else { // Değilse chat arayüzünü göster renderChatInterface(chatContainer); } }); } if (noButton) { noButton.addEventListener('click', () => { saveUserConsent(false); chatContainer.removeChild(consentForm); // Onay vermezse sohbet arayüzünü gösterme const widgetContainer = document.getElementById('kayra-chatbot-widget'); if (widgetContainer) { const toggleBtn = widgetContainer.querySelector('.kayra-chat-toggle'); if (toggleBtn) toggleBtn.style.display = 'flex'; } chatContainer.style.display = 'none'; isWidgetOpen = false; saveWidgetState(false); }); } }, 0); chatContainer.appendChild(consentForm); return true; } // Kullanıcı bilgileri formunu oluştur function renderUserInfoForm(chatContainer) { // Gerekli alanları belirle const nameRequired = widgetConfig.name_required; const phoneRequired = widgetConfig.phone_required; const emailRequired = widgetConfig.email_required; const customRequired = widgetConfig.custom_required; const customFieldName = widgetConfig.custom_field_name || t('otherInfo'); // Form container const formContainer = document.createElement('div'); formContainer.className = 'kayra-form-container'; let formHtml = `
${t('formTitle')}
`; // Ad Soyad if (nameRequired) { formHtml += `
`; } else { formHtml += `
`; } // Telefon Numarası if (phoneRequired) { formHtml += `
`; } else { formHtml += `
`; } // Email if (emailRequired) { formHtml += `
`; } else { formHtml += `
`; } // Özel Alan if (widgetConfig.custom_field_name) { if (customRequired) { formHtml += `
`; } else { formHtml += `
`; } } // Devam etme düğmeleri formHtml += `
`; formContainer.innerHTML = formHtml; chatContainer.appendChild(formContainer); // Butonları dinle - DOM'dan bularak setTimeout(() => { const submitButton = document.getElementById('kayra-submit-info'); const skipButton = document.getElementById('kayra-skip-info'); if (submitButton) { console.log('Submit info butonu bulundu ve event listener ekleniyor'); submitButton.addEventListener('click', function() { console.log('Submit info butonu tıklandı'); // Zorunlu alanları kontrol et let isValid = true; const userInfo = {}; if (nameRequired) { const nameInput = document.getElementById('kayra-user-name'); if (nameInput && !nameInput.value.trim()) { nameInput.classList.add('kayra-input-error'); isValid = false; } else if (nameInput) { nameInput.classList.remove('kayra-input-error'); userInfo.name = nameInput.value.trim(); } } else { const nameInput = document.getElementById('kayra-user-name'); userInfo.name = nameInput ? nameInput.value.trim() : ''; } if (phoneRequired) { const phoneInput = document.getElementById('kayra-user-phone'); if (phoneInput && !phoneInput.value.trim()) { phoneInput.classList.add('kayra-input-error'); isValid = false; } else if (phoneInput) { phoneInput.classList.remove('kayra-input-error'); userInfo.phone = phoneInput.value.trim(); } } else { const phoneInput = document.getElementById('kayra-user-phone'); userInfo.phone = phoneInput ? phoneInput.value.trim() : ''; } if (emailRequired) { const emailInput = document.getElementById('kayra-user-email'); if (emailInput && (!emailInput.value.trim() || !isValidEmail(emailInput.value.trim()))) { emailInput.classList.add('kayra-input-error'); isValid = false; } else if (emailInput) { emailInput.classList.remove('kayra-input-error'); userInfo.email = emailInput.value.trim(); } } else { const emailInput = document.getElementById('kayra-user-email'); userInfo.email = emailInput ? emailInput.value.trim() : ''; } if (customRequired && widgetConfig.custom_field_name) { const customInput = document.getElementById('kayra-user-custom'); if (customInput && !customInput.value.trim()) { customInput.classList.add('kayra-input-error'); isValid = false; } else if (customInput) { customInput.classList.remove('kayra-input-error'); userInfo.custom = customInput.value.trim(); } } else if (widgetConfig.custom_field_name) { const customInput = document.getElementById('kayra-user-custom'); userInfo.custom = customInput ? customInput.value.trim() : ''; } if (isValid) { // Kullanıcı bilgilerini kaydet saveUserInfo(userInfo); // Formu kaldır chatContainer.removeChild(formContainer); // Chat arayüzünü göster renderChatInterface(chatContainer); // Event listener'ları yeniden ayarla setTimeout(() => { setupAllEventListeners(); }, 100); } }); } if (skipButton) { console.log('Skip info butonu bulundu ve event listener ekleniyor'); skipButton.addEventListener('click', function() { console.log('Skip info butonu tıklandı'); // Hiçbir zorunlu alan yoksa geçişe izin ver, aksi takdirde kontrol et if (!nameRequired && !phoneRequired && !emailRequired && !customRequired) { // Boş bir kullanıcı bilgisi kaydet saveUserInfo({}); // Formu kaldır chatContainer.removeChild(formContainer); // Chat arayüzünü göster renderChatInterface(chatContainer); // Event listener'ları yeniden ayarla setTimeout(() => { setupAllEventListeners(); }, 100); } else { alert(t('requiredFields')); } }); } }, 100); } // Email doğrulama function isValidEmail(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } // Kullanıcı onay durumunu kaydet ve kontrol et function saveUserConsent(hasConsented) { try { localStorage.setItem(STORAGE_KEY_CONSENT, hasConsented ? 'true' : 'false'); } catch (error) { console.error('Kullanıcı onayı kaydedilirken hata:', error); } } // Tüm widget verilerini temizle function resetAllWidgetData() { try { // Tüm verileri localStorage'dan temizle localStorage.removeItem(STORAGE_KEY_HISTORY); localStorage.removeItem(STORAGE_KEY_CONSENT); localStorage.removeItem(STORAGE_KEY_USER_INFO); // Sohbetin sıfırlandığını işaretle localStorage.setItem(`kayra_chat_reset_${widgetId}`, 'true'); // Widget'ı kapat localStorage.setItem(STORAGE_KEY_OPEN, 'false'); // Geçmiş mesajları temizle messageHistory = []; return true; } catch (error) { console.error('Widget verileri temizlenirken hata:', error); return false; } } function hasUserConsent() { try { return localStorage.getItem(STORAGE_KEY_CONSENT) === 'true'; } catch (error) { console.error('Kullanıcı onayı kontrol edilirken hata:', error); return false; } } // Kullanıcı bilgilerini kaydet ve kontrol et function saveUserInfo(userInfo) { try { localStorage.setItem(STORAGE_KEY_USER_INFO, JSON.stringify(userInfo)); } catch (error) { console.error('Kullanıcı bilgileri kaydedilirken hata:', error); } } function hasUserInfo() { try { return localStorage.getItem(STORAGE_KEY_USER_INFO) !== null; } catch (error) { console.error('Kullanıcı bilgileri kontrol edilirken hata:', error); return false; } } function getUserInfo() { try { const userInfoData = localStorage.getItem(STORAGE_KEY_USER_INFO); return userInfoData ? JSON.parse(userInfoData) : null; } catch (error) { console.error('Kullanıcı bilgileri alınırken hata:', error); return null; } } // Tüm event listener'ları ayarla - bu fonksiyon ayrı olarak herhangi bir zamanda çağrılabilir function setupAllEventListeners() { const widgetContainer = document.getElementById('kayra-chatbot-widget'); if (!widgetContainer) { console.error('Widget container bulunamadı!'); return; } const toggleButton = widgetContainer.querySelector('.kayra-chat-toggle'); const chatContainer = widgetContainer.querySelector('.kayra-chat-container'); const closeButton = widgetContainer.querySelector('.kayra-chat-close'); const resetButton = widgetContainer.querySelector('.kayra-reset-chat'); console.log('Bulunan elementler:', { toggleButton: !!toggleButton, chatContainer: !!chatContainer, closeButton: !!closeButton, resetButton: !!resetButton }); // Toggle butonu event listener'ı if (toggleButton) { // Önceki event listener'ları kaldırmak için klonla ve değiştir const newToggleButton = toggleButton.cloneNode(true); toggleButton.parentNode.replaceChild(newToggleButton, toggleButton); newToggleButton.addEventListener('click', () => { console.log('Toggle button tıklandı'); isWidgetOpen = !isWidgetOpen; chatContainer.style.display = isWidgetOpen ? 'flex' : 'none'; newToggleButton.style.display = isWidgetOpen ? 'none' : 'flex'; // Son aktivite zamanını güncelle updateLastActivity(); // Açık/kapalı durumunu kaydet - localStorage'a kullanıcı tercihini kaydet console.log('Kullanıcı widget tercihini değiştirdi:', isWidgetOpen ? 'AÇIK' : 'KAPALI'); saveWidgetState(isWidgetOpen); // Element referanslarını güncelle çünkü DOM değişmiş olabilir setupChatInputListeners(); // KVKK kontrolü ve kullanıcı bilgi kontrolü checkFormsStatus(); }); } // Chat kapatma butonu event listener'ı if (closeButton) { // Önceki event listener'ları kaldırmak için klonla ve değiştir const newCloseButton = closeButton.cloneNode(true); closeButton.parentNode.replaceChild(newCloseButton, closeButton); newCloseButton.addEventListener('click', () => { console.log('Close button tıklandı'); isWidgetOpen = false; chatContainer.style.display = 'none'; const toggleBtn = widgetContainer.querySelector('.kayra-chat-toggle'); if (toggleBtn) toggleBtn.style.display = 'flex'; // Konuşmayı tamamlandı olarak işaretle markConversationAsCompleted(); // Son aktivite zamanını güncelle updateLastActivity(); // Açık/kapalı durumunu kaydet - localStorage'a kullanıcı tercihini kaydet console.log('Kullanıcı widget\'ı kapattı, tercih kaydediliyor: KAPALI'); saveWidgetState(false); }); } // Reset butonu event listener'ı if (resetButton) { // Önceki event listener'ları kaldırmak için klonla ve değiştir const newResetButton = resetButton.cloneNode(true); resetButton.parentNode.replaceChild(newResetButton, resetButton); newResetButton.addEventListener('click', () => { console.log('Reset button tıklandı'); // Onay isteyin if (confirm(t('resetConfirm'))) { // Konuşmayı tamamlandı olarak işaretle markConversationAsCompleted(); // Tüm verileri temizle if (resetAllWidgetData()) { // Mesaj listesini temizle const messagesContainer = widgetContainer.querySelector('.kayra-chat-messages'); if (messagesContainer) { messagesContainer.innerHTML = ''; // Hoşgeldin mesajını yeniden ekle const welcomeMessage = document.createElement('div'); welcomeMessage.className = 'kayra-message kayra-bot-message'; // Dil'e uygun hoşgeldin mesajını seç let welcomeText = t('welcomeDefault'); if (widgetLang === 'tr' && widgetConfig.welcome_message_tr) { welcomeText = widgetConfig.welcome_message_tr; } else if (widgetLang === 'en' && widgetConfig.welcome_message_en) { welcomeText = widgetConfig.welcome_message_en; } else if (widgetConfig.welcome_message) { // Eski versiyon uyumluluğu için welcomeText = widgetConfig.welcome_message; } welcomeMessage.innerHTML = `
${widgetConfig.bot_name || 'Chat Bot'}
${welcomeText}
`; messagesContainer.appendChild(welcomeMessage); } // Son aktivite zamanını güncelle updateLastActivity(); // Widget'ı kapat chatContainer.style.display = 'none'; const toggleBtn = widgetContainer.querySelector('.kayra-chat-toggle'); if (toggleBtn) toggleBtn.style.display = 'flex'; isWidgetOpen = false; } } }); } // Chat input için event listener'ları ayarla setupChatInputListeners(); } // Chat input için event listener'ları ayarla - bu fonksiyon ayrı olarak da çağrılabilir function setupChatInputListeners() { const widgetContainer = document.getElementById('kayra-chatbot-widget'); if (!widgetContainer) return; const chatInput = widgetContainer.querySelector('.kayra-chat-input'); const sendButton = widgetContainer.querySelector('.kayra-send-button'); const messagesContainer = widgetContainer.querySelector('.kayra-chat-messages'); if (!chatInput || !sendButton) { console.log('Chat input veya send button bulunamadı'); return; // Henüz elementler hazır değilse çık } console.log('Chat input listener\'ları ayarlanıyor...'); // Önceki event listener'ları temizlemek için klonları oluştur ve değiştir const newChatInput = chatInput.cloneNode(true); const newSendButton = sendButton.cloneNode(true); chatInput.parentNode.replaceChild(newChatInput, chatInput); sendButton.parentNode.replaceChild(newSendButton, sendButton); // Mesaj gönderme (buton) newSendButton.addEventListener('click', () => { console.log('Send button tıklandı'); sendMessage(newChatInput, messagesContainer); }); // Mesaj gönderme (enter tuşu) newChatInput.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { console.log('Enter tuşu basıldı'); e.preventDefault(); sendMessage(newChatInput, messagesContainer); } // Textarea yüksekliğini içeriğe göre ayarla setTimeout(() => { newChatInput.style.height = 'auto'; newChatInput.style.height = `${Math.min(newChatInput.scrollHeight, 120)}px`; }, 0); }); // İlk odaklanma if (isWidgetOpen) { setTimeout(() => { newChatInput.focus(); }, 300); } } // Mesaj gönderme fonksiyonu function sendMessage(chatInput, messagesContainer) { const message = chatInput.value.trim(); if (!message) return; // Log ekle console.log('Mesaj gönderiliyor:', message); // Kullanıcı mesajını ekle addMessage(message, 'user'); // Input'u temizle chatInput.value = ''; chatInput.style.height = 'auto'; // Son aktivite zamanını güncelle updateLastActivity(); // Bottan yanıt iste getBotResponse(message); } // Mesaj ekle function addMessage(message, sender) { if (!message) return; const widgetContainer = document.getElementById('kayra-chatbot-widget'); if (!widgetContainer) return; const messagesContainer = widgetContainer.querySelector('.kayra-chat-messages'); if (!messagesContainer) return; // Mesaj geçmişini güncelle messageHistory.push({ sender, message }); // Mesaj geçmişini localStorage'a kaydet saveChatHistory(); // Kullanıcı adını al (varsa) const userInfo = getUserInfo(); const userName = (userInfo && userInfo.name) ? userInfo.name : t('you'); // Mesaj elementi oluştur const messageElement = document.createElement('div'); messageElement.className = `kayra-message kayra-${sender}-message`; if (sender === 'bot') { messageElement.innerHTML = `
${widgetConfig.bot_name || 'Chat Bot'}
${message}
`; // Bot mesajı içindeki bağlantıları aktif hale getir const messageContent = messageElement.querySelector('.kayra-message-content'); // HTML içeriği olduğu gibi kullan, dış etiketleri dokunma } else { // Kullanıcı mesajını güvenli bir şekilde işle const sanitizedMessage = escapeHTML(message); messageElement.innerHTML = `
${userName}
${sanitizedMessage}
`; } // Mesajı ekle messagesContainer.appendChild(messageElement); // Otomatik scroll messagesContainer.scrollTop = messagesContainer.scrollHeight; } // HTML özel karakterleri escaping function escapeHTML(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // Bot yanıtı al async function getBotResponse(userMessage) { // Yükleniyor göster const widgetContainer = document.getElementById('kayra-chatbot-widget'); const messagesContainer = widgetContainer.querySelector('.kayra-chat-messages'); const loadingElement = document.createElement('div'); loadingElement.className = 'kayra-message kayra-bot-message kayra-loading'; loadingElement.innerHTML = `
${widgetConfig.bot_name || 'Chat Bot'}
`; messagesContainer.appendChild(loadingElement); messagesContainer.scrollTop = messagesContainer.scrollHeight; try { // API'dan yanıt al - URL'yi routes/api.php'deki tanımla eşleştiriyoruz const response = await fetch(`${baseUrl}/api/chatbot-widgets/${widgetId}/chat`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: userMessage, history: messageHistory.slice(-6), // Son 6 mesajı gönder (3 tur) lang: widgetLang, // Dil bilgisini API'ye gönder allow_html: true // HTML yanıtları etkinleştir }) }); if (!response.ok) throw new Error('Bot yanıtı alınamadı'); const data = await response.json(); // Yükleniyor göstergesini kaldır messagesContainer.removeChild(loadingElement); // API yanıtını kontrol et if (!data.success && data.message) { // API anahtarı ile ilgili hata mesajını kontrol et if (data.message.toLowerCase().includes('api') && (data.message.toLowerCase().includes('key') || data.message.toLowerCase().includes('anahtar'))) { // API anahtarı ile ilgili özel hata mesajı const apiErrorMsg = widgetLang === 'tr' ? 'Yapay zeka yanıt sistemi yapılandırılmamış. Lütfen site yöneticisi ile iletişime geçin ve Google Gemini API anahtarının tanımlanması gerektiğini belirtin.' : 'AI response system is not configured. Please contact the site administrator and mention that a Google Gemini API key needs to be set up.'; addMessage(apiErrorMsg, 'bot'); } else { // Diğer API hataları addMessage(data.message || t('errorMessage'), 'bot'); } } else { // Normal yanıt const botMessage = data.message || t('noResponseError'); addMessage(botMessage, 'bot'); } // Son aktivite zamanını güncelle updateLastActivity(); } catch (error) { console.error('Kayra Chatbot Response Error:', error); // Yükleniyor göstergesini kaldır messagesContainer.removeChild(loadingElement); // Hata mesajı göster addMessage(t('errorMessage'), 'bot'); // Son aktivite zamanını güncelle updateLastActivity(); } } // Widget'ı başlat function initWidget() { console.log('Widget başlatılıyor...'); // Önce CSS yükle loadStyles(); // Sayfa kapanış olayını dinle window.addEventListener('beforeunload', handlePageExit); // Önce sohbet geçmişini yükle - SADECE mesaj geçmişini yüklemek için console.log('Mesaj geçmişi yükleniyor...'); loadChatHistory(); // Sonra widget yapılandırmasını al ve görüntüle // is_open kontrolü burada yapılacak console.log('Widget yapılandırması alınıyor...'); fetchWidgetConfig().then(config => { if (config) { console.log('Widget yapılandırması yüklendi, DOM event listener\'ları ayarlanıyor...'); // Event listener'ları ayarla setTimeout(() => { const widgetContainer = document.getElementById('kayra-chatbot-widget'); if (widgetContainer) { setupAllEventListeners(); console.log('Event listener\'lar yüklendi.'); } }, 500); } else { console.error('Widget yapılandırması yüklenemedi, widget görüntülenemeyecek.'); } }) .catch(error => { console.error('Widget yapılandırması yüklenirken hata oluştu:', error); }); } // Document ready olduğunda başlat if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initWidget); } else { initWidget(); } // Sayfa tamamen yüklendiğinde event listener'ları yeniden ayarla window.addEventListener('load', () => { console.log('Sayfa tamamen yüklendi, event listener\'lar yeniden ayarlanıyor...'); setTimeout(() => { setupAllEventListeners(); }, 1000); }); // Sohbet geçmişini temizle function clearChatHistory() { try { localStorage.removeItem(STORAGE_KEY_HISTORY); // Sohbetin sıfırlandığını işaretle localStorage.setItem(`kayra_chat_reset_${widgetId}`, 'true'); messageHistory = []; return true; } catch (error) { console.error('Sohbet geçmişi temizlenirken hata:', error); return false; } } // Son aktivite zamanını kaydet ve kontrol et function updateLastActivity() { try { localStorage.setItem(STORAGE_KEY_LAST_ACTIVITY, Date.now().toString()); } catch (error) { console.error('Son aktivite kaydedilirken hata:', error); } } function checkSessionTimeout() { try { const lastActivity = localStorage.getItem(STORAGE_KEY_LAST_ACTIVITY); if (lastActivity) { const lastActiveTime = parseInt(lastActivity, 10); const currentTime = Date.now(); const minutesPassed = (currentTime - lastActiveTime) / (1000 * 60); if (minutesPassed > CHAT_TIMEOUT_MINUTES) { // Oturum zaman aşımına uğradı, sohbeti temizle clearChatHistory(); return true; // Zaman aşımı oldu } } return false; // Zaman aşımı olmadı } catch (error) { console.error('Oturum zaman aşımı kontrolü sırasında hata:', error); return false; } } // Sayfa kapanma olayını kaydet function handlePageExit() { try { localStorage.setItem(STORAGE_KEY_LAST_EXIT, Date.now().toString()); } catch (error) { console.error('Sayfa çıkış zamanı kaydedilirken hata:', error); } } // Sayfa açılma olayını kontrol et, uzun süre kapalı kaldıysa sohbeti temizle function checkPageReentry() { try { const lastExit = localStorage.getItem(STORAGE_KEY_LAST_EXIT); if (lastExit) { const lastExitTime = parseInt(lastExit, 10); const currentTime = Date.now(); const minutesPassed = (currentTime - lastExitTime) / (1000 * 60); if (minutesPassed > CHAT_TIMEOUT_MINUTES) { // Sayfa uzun süre kapalı kalmış, sohbeti temizle console.log(`Sayfa ${minutesPassed.toFixed(2)} dakika kapalı kaldı. Sohbet temizleniyor.`); clearChatHistory(); return true; // Zaman aşımı oldu } else { console.log(`Sayfa ${minutesPassed.toFixed(2)} dakika kapalı kaldı. Sohbet korunuyor.`); } } return false; // Zaman aşımı olmadı } catch (error) { console.error('Sayfa yeniden giriş kontrolü sırasında hata:', error); return false; } } // Konuşmayı tamamlandı olarak işaretle function markConversationAsCompleted() { localStorage.setItem(`kayra_chat_completed_${widgetId}`, 'true'); // Hemen sunucuya gönder if (messageHistory.length > 0) { saveConversationToServer(); } } })();