Files
eveAI/eveai_chat_client/static/assets/js/ChatApp.js

1107 lines
43 KiB
JavaScript

// Import all components via barrel export
import { TypingIndicator, FormField, DynamicForm, ChatMessage, MessageHistory, ProgressTracker, LanguageSelector, ChatInput } from './components/index.js';
// Main Chat Application
// Main Chat Application - geëxporteerd als module
export const ChatApp = {
name: 'ChatApp',
components: {
TypingIndicator,
FormField,
DynamicForm,
ChatMessage,
MessageHistory,
ProgressTracker,
ChatInput
},
data() {
// Maak een lokale kopie van de chatConfig om undefined errors te voorkomen
const chatConfig = window.chatConfig || {};
const settings = chatConfig.settings || {};
const initialLanguage = chatConfig.language || 'nl';
const originalExplanation = chatConfig.explanation || '';
const tenantMake = chatConfig.tenantMake || {};
return {
// Tenant info
tenantName: tenantMake.name || 'EveAI',
tenantLogoUrl: tenantMake.logo_url || '',
// Taal gerelateerde data
currentLanguage: initialLanguage,
supportedLanguageDetails: chatConfig.supportedLanguageDetails || {},
allowedLanguages: chatConfig.allowedLanguages || ['nl', 'en', 'fr', 'de'],
supportedLanguages: chatConfig.supportedLanguages || [],
originalExplanation: originalExplanation,
explanation: chatConfig.explanation || '',
// Chat-specific data
currentMessage: '',
allMessages: [],
isTyping: false,
isLoading: false,
isSubmittingForm: false,
messageIdCounter: 1,
formValues: {},
currentInputFormData: null,
// API prefix voor endpoints
apiPrefix: chatConfig.apiPrefix || '',
// Configuration from Flask/server
conversationId: chatConfig.conversationId || 'default',
userId: chatConfig.userId || null,
userName: chatConfig.userName || '',
// Settings met standaard waarden en overschreven door server config
settings: {
maxMessageLength: settings.maxMessageLength || 2000,
allowFileUpload: settings.allowFileUpload === true,
allowVoiceMessage: settings.allowVoiceMessage === true,
autoScroll: settings.autoScroll === true
},
// UI state
isMobile: window.innerWidth <= 768,
showSidebar: window.innerWidth > 768,
// Advanced features
messageSearch: '',
filteredMessages: [],
isSearching: false
};
},
computed: {
// Keep existing computed from base.html
compiledExplanation() {
if (typeof marked === 'function') {
return marked(this.explanation);
} else if (marked && typeof marked.parse === 'function') {
return marked.parse(this.explanation.replace(/\[\[(.*?)\]\]/g, '<strong>$1</strong>'));
} else {
console.error('Marked library not properly loaded');
return this.explanation;
}
},
displayMessages() {
return this.isSearching ? this.filteredMessages : this.allMessages;
},
hasMessages() {
return this.allMessages.length > 0;
},
displayLanguages() {
// Filter de ondersteunde talen op basis van de toegestane talen
if (!this.supportedLanguages || !this.allowedLanguages) {
return [];
}
return this.supportedLanguages.filter(lang =>
this.allowedLanguages.includes(lang.code)
);
}
},
mounted() {
console.log('🔍 [DEBUG] ChatApp mounted');
console.log('🔍 [DEBUG] ChatApp data:', {
tenantName: this.tenantName,
currentLanguage: this.currentLanguage,
allowedLanguages: this.allowedLanguages,
conversationId: this.conversationId,
userId: this.userId
});
// Log beschikbare componenten
console.log('🔍 [DEBUG] Geregistreerde componenten:', {
messageHistory: !!this.$options.components.MessageHistory,
chatInput: !!this.$options.components.ChatInput
});
// Render de component
this.renderComponent();
console.log('🔍 [DEBUG] ChatApp mounted');
console.log('🔍 [DEBUG] Props en data:', {
currentLanguage: this.currentLanguage,
allowedLanguages: this.allowedLanguages,
tenantName: this.tenantName
});
this.initializeChat();
this.setupEventListeners();
// Render de component
this.renderComponent();
},
beforeUnmount() {
this.cleanup();
},
// Nieuwe methode om de component direct te renderen
renderComponent() {
console.log('🔍 [DEBUG] ChatApp.renderComponent() aangeroepen');
// Hier kunnen we directe DOM-manipulatie toevoegen indien nodig
// Vergelijkbaar met LanguageSelector.renderComponent()
},
methods: {
// Initialization
initializeChat() {
console.log('Initializing chat application...');
// Load historical messages from server
this.loadHistoricalMessages();
console.log('Nr of messages:', this.allMessages.length);
// Add welcome message if no history
if (this.allMessages.length === 0) {
this.addWelcomeMessage();
}
// Focus input after initialization
this.$nextTick(() => {
this.focusChatInput();
});
},
loadHistoricalMessages() {
// Veilige toegang tot messages met fallback
const chatConfig = window.chatConfig || {};
const historicalMessages = chatConfig.messages || [];
if (historicalMessages.length > 0) {
this.allMessages = historicalMessages
.filter(msg => msg !== null && msg !== undefined) // Filter null/undefined berichten uit
.map(msg => {
// Zorg voor een correct geformatteerde bericht-object
return {
id: this.messageIdCounter++,
content: typeof msg === 'string' ? msg : (msg.content || ''),
sender: msg.sender || 'ai',
type: msg.type || 'text',
timestamp: msg.timestamp || new Date().toISOString(),
formData: msg.formData || null,
status: msg.status || 'delivered'
};
});
console.log(`Loaded ${this.allMessages.length} historical messages`);
}
},
async addWelcomeMessage() {
console.log('Sending initialize message to backend');
// Toon typing indicator
this.isTyping = true;
this.isLoading = true;
try {
// Verzamel gegevens voor de API call
const apiData = {
message: 'Initialize',
conversation_id: this.conversationId,
user_id: this.userId,
language: this.currentLanguage
};
const response = await this.callAPI('/api/send_message', apiData);
// Verberg typing indicator
this.isTyping = false;
// Voeg AI response toe met task_id voor tracking
const aiMessage = this.addMessage(
'',
'ai',
'text'
);
// Voeg task_id toe als beschikbaar
if (response.task_id) {
console.log('Monitoring Initialize Task ID: ', response.task_id);
aiMessage.taskId = response.task_id;
}
} catch (error) {
console.error('Error sending initialize message:', error);
this.isTyping = false;
// Voeg standaard welkomstbericht toe als fallback
this.addMessage(
'Hallo! Ik ben je AI assistant. Vraag gerust om een formulier zoals "contactformulier" of "bestelformulier"!',
'ai',
'text'
);
} finally {
this.isLoading = false;
}
},
setupEventListeners() {
// Window resize listener
window.addEventListener('resize', this.handleResize);
// Keyboard shortcuts
document.addEventListener('keydown', this.handleGlobalKeydown);
// Luister naar taalwijzigingen via custom events
document.addEventListener('language-changed', (event) => {
if (event.detail && event.detail.language) {
console.log('ChatApp received language-changed event:', event.detail.language);
this.handleLanguageChange(event.detail.language);
}
});
},
cleanup() {
window.removeEventListener('resize', this.handleResize);
document.removeEventListener('keydown', this.handleGlobalKeydown);
},
// Taal gerelateerde functionaliteit
handleLanguageChange(newLanguage) {
if (this.currentLanguage !== newLanguage) {
console.log(`ChatApp: Taal gewijzigd van ${this.currentLanguage} naar ${newLanguage}`);
this.currentLanguage = newLanguage;
// Vertaal de sidebar
this.translateSidebar(newLanguage);
// Sla de taalvoorkeur op voor toekomstige API calls
this.storeLanguagePreference(newLanguage);
// Stuur language-changed event voor andere componenten (zoals ChatInput)
// Dit wordt gedaan via het event systeem, waardoor we geen directe referentie nodig hebben
const event = new CustomEvent('language-changed', {
detail: { language: newLanguage }
});
document.dispatchEvent(event);
}
},
// Maak de handleLanguageChange methode toegankelijk van buitenaf
// Deze functie wordt opgeroepen door het externe LanguageSelector component
__handleExternalLanguageChange(newLanguage) {
this.handleLanguageChange(newLanguage);
},
storeLanguagePreference(language) {
// Sla op in localStorage voor persistentie
localStorage.setItem('preferredLanguage', language);
// Update chatConfig voor toekomstige API calls
if (window.chatConfig) {
window.chatConfig.language = language;
}
console.log(`Taalvoorkeur opgeslagen: ${language}`);
},
async translateSidebar(language) {
console.log(`Sidebar wordt vertaald naar: ${language}`);
// Haal de originele tekst op
const originalText = this.originalExplanation || this.explanation;
try {
// Controleer of TranslationClient beschikbaar is
if (!window.TranslationClient || typeof window.TranslationClient.translate !== 'function') {
console.error('TranslationClient.translate is niet beschikbaar');
this.showTranslationIndicator(language, 'Vertaling niet beschikbaar', false);
return;
}
// Toon loading indicator
this.showTranslationIndicator(language, 'Bezig met vertalen...');
console.log('API prefix voor vertaling:', this.apiPrefix);
// Gebruik TranslationClient met de juiste parameters
const response = await window.TranslationClient.translate(
originalText,
language,
null, // source_lang (auto-detect)
'sidebar_explanation', // context
this.apiPrefix // API prefix voor tenant routing
);
if (response.success) {
// Update de explanation variabele
console.log('Translated text: ' + response.translated_text);
this.explanation = response.translated_text;
// 1. Update de Vue instance
if (window.__vueApp && window.__vueApp._instance) {
window.__vueApp._instance.proxy.explanation = response.translated_text;
}
// 2. Update direct het DOM-element via marked voor onmiddellijke weergave
const sidebarElement = document.querySelector('.sidebar-explanation');
if (sidebarElement) {
console.log('DOM-element gevonden, directe update toepassen');
// Gebruik de marked library om de markdown naar HTML te converteren
let htmlContent;
if (typeof marked === 'function') {
htmlContent = marked(response.translated_text);
} else if (marked && typeof marked.parse === 'function') {
htmlContent = marked.parse(response.translated_text);
} else {
htmlContent = response.translated_text;
}
// Update de inhoud direct
sidebarElement.innerHTML = htmlContent;
} else {
console.error('Sidebar explanation element niet gevonden in DOM');
}
this.showTranslationIndicator(language, 'Vertaling voltooid!', true);
} else {
console.error('Vertaling mislukt:', response.error);
this.showTranslationIndicator(language, 'Vertaling mislukt', false);
}
} catch (error) {
console.error('Fout bij vertalen sidebar:', error);
this.showTranslationIndicator(language, 'Vertaling mislukt', false);
}
},
// Message management
addMessage(content, sender, type = 'text', formData = null, formValues = null) {
const message = {
id: this.messageIdCounter++,
content,
sender,
type,
formData,
formValues,
timestamp: new Date().toISOString(),
status: sender === 'user' ? 'sent' : 'delivered'
};
this.allMessages.push(message);
// Initialize form values if it's a form and no values were provided
if (type === 'form' && formData && !formValues) {
// Vue 3 compatibele manier om reactieve objecten bij te werken
this.formValues[message.id] = {};
formData.fields.forEach(field => {
const fieldName = field.name || field.id;
if (fieldName) {
this.formValues[message.id][fieldName] = field.defaultValue || '';
}
});
}
// Update search results if searching
if (this.isSearching) {
this.performSearch();
}
return message;
},
showTranslationIndicator(language, message, success = null) {
const explanationElement = document.querySelector('.sidebar-explanation');
if (explanationElement) {
// Verwijder eventuele bestaande indicators
const existingIndicator = explanationElement.querySelector('.language-change-indicator');
if (existingIndicator) {
existingIndicator.remove();
}
// Voeg nieuwe indicator toe
const indicator = document.createElement('div');
indicator.className = 'language-change-indicator';
if (success === true) indicator.classList.add('success');
if (success === false) indicator.classList.add('error');
indicator.innerHTML = `<small>${message}</small>`;
explanationElement.prepend(indicator);
// Verwijder na 3 seconden, behalve bij loading
if (success !== null) {
setTimeout(() => {
if (explanationElement.contains(indicator)) {
indicator.remove();
}
}, 3000);
}
}
},
// Helper functie om formulierdata toe te voegen aan bestaande berichten
attachFormDataToMessage(messageId, formData, formValues) {
const message = this.allMessages.find(m => m.id === messageId);
if (message) {
message.formData = formData;
message.formValues = formValues;
}
},
updateCurrentMessage(value) {
this.currentMessage = value;
},
// Message sending (alleen voor gewone tekstberichten, geen formulieren)
async sendMessage() {
const text = this.currentMessage.trim();
// Controleer of we kunnen verzenden
if (!text || this.isLoading) return;
console.log('Sending text message:', text);
// Add user message
const userMessage = this.addMessage(text, 'user', 'text');
// Wis input
this.currentMessage = '';
// Show typing and loading state
this.isTyping = true;
this.isLoading = true;
try {
// Verzamel gegevens voor de API call
const apiData = {
message: text,
conversation_id: this.conversationId,
user_id: this.userId,
language: this.currentLanguage
};
const response = await this.callAPI('/api/send_message', apiData);
// Hide typing indicator
this.isTyping = false;
// Mark user message as delivered
userMessage.status = 'delivered';
// Add AI response
if (response.type === 'form') {
this.addMessage('', 'ai', 'form', response.formData);
} else {
// Voeg het bericht toe met task_id voor tracking - initieel leeg
const aiMessage = this.addMessage(
'',
'ai',
'text'
);
// Voeg task_id toe als beschikbaar
if (response.task_id) {
console.log('Monitoring Task ID: ', response.task_id);
aiMessage.taskId = response.task_id;
}
}
} catch (error) {
console.error('Error sending message:', error);
this.isTyping = false;
// Mark user message as failed
userMessage.status = 'failed';
this.addMessage(
'Sorry, er ging iets mis bij het verzenden van je bericht. Probeer het opnieuw.',
'ai',
'error'
);
} finally {
this.isLoading = false;
}
},
async submitFormFromInput(formValues) {
this.isSubmittingForm = true;
if (!this.currentInputFormData) {
console.error('No form data available');
return;
}
console.log('Form values received:', formValues);
console.log('Current input form data:', this.currentInputFormData);
try {
// Maak een user message met formuliergegevens én eventuele tekst
const userMessage = this.addMessage(
this.currentMessage.trim(), // Voeg tekst toe als die er is
'user',
'text'
);
// Voeg formuliergegevens toe aan het bericht
userMessage.formData = this.currentInputFormData;
userMessage.formValues = formValues;
// Reset het tekstbericht
this.currentMessage = '';
this.$emit('update-message', '');
// Toon laad-indicator
this.isTyping = true;
this.isLoading = true;
// Verzamel gegevens voor de API call
const apiData = {
message: userMessage.content,
conversation_id: this.conversationId,
user_id: this.userId,
form_values: formValues // Voeg formuliergegevens toe aan API call
};
// Verstuur bericht naar de API
const response = await this.callAPI('/api/send_message', apiData);
// Verberg de typing indicator
this.isTyping = false;
// Markeer het gebruikersbericht als afgeleverd
userMessage.status = 'delivered';
// Voeg AI response toe met task_id voor tracking
const aiMessage = this.addMessage(
'',
'ai',
'text'
);
if (response.task_id) {
console.log('Monitoring Task ID: ', response.task_id);
aiMessage.taskId = response.task_id;
}
// Reset formulier na succesvolle verzending
this.currentInputFormData = null;
} catch (error) {
console.error('Error submitting form:', error);
this.addMessage(
'Sorry, er ging iets mis bij het verzenden van het formulier. Probeer het opnieuw.',
'ai',
'text'
);
// Wis ook hier het formulier na een fout
this.currentInputFormData = null;
} finally {
this.isSubmittingForm = false;
this.isLoading = false;
}
},
// Message actions
retryMessage(messageId) {
const message = this.allMessages.find(m => m.id === messageId);
if (message && message.status === 'failed') {
// Retry sending the message
this.currentMessage = message.content;
this.removeMessage(messageId);
this.sendMessage();
}
},
submitForm(formValues) {
console.log('🔍 [DEBUG] Formulier verzenden:', formValues);
if (!formValues || this.isLoading) return;
// Markeer formulier als bezig met verzenden
this.isSubmittingForm = true;
// Voeg gebruikersformulier toe aan chat
this.addFormMessage(formValues, 'user');
// Verstuur naar backend
this.sendFormToBackend(formValues);
// Reset input form
this.currentInputFormData = null;
},
sendFormToBackend(formValues) {
console.log('🔍 [DEBUG] Formulier naar backend versturen', formValues);
// Implementatie voor het versturen van formulier data
this.isSubmittingForm = false;
},
sendMessageToBackend(message) {
console.log('🔍 [DEBUG] Bericht naar backend versturen', message);
// Implementatie voor het versturen van berichten
},
addFormMessage(formValues, sender) {
console.log('🔍 [DEBUG] Formulier bericht toevoegen:', formValues);
// Implementatie voor het toevoegen van een formulier bericht
},
focusChatInput() {
// Focus op de chat input als deze beschikbaar is
this.$nextTick(() => {
// Controleer of $el beschikbaar is
if (!this.$el) {
console.warn('$el is niet beschikbaar in focusChatInput');
return;
}
// Probeer de input te vinden en focus
try {
const chatInputComponent = this.$el.querySelector('.chat-input-container');
if (chatInputComponent) {
console.log('🔍 [DEBUG] Focus op chat input');
// Probeer een input element te vinden om focus op te zetten
const inputElement = chatInputComponent.querySelector('input, textarea');
if (inputElement) {
inputElement.focus();
}
}
} catch (error) {
console.error('Fout bij focussen op chat input:', error);
}
});
},
removeMessage(messageId) {
const index = this.allMessages.findIndex(m => m.id === messageId);
if (index !== -1) {
this.allMessages.splice(index, 1);
// Verwijder ook eventuele formuliergegevens
if (this.formValues[messageId]) {
delete this.formValues[messageId];
}
}
},
// File handling
async handleFileUpload(file) {
console.log('Uploading file:', file.name);
// Add file message
const fileMessage = this.addMessage('', 'user', 'file', {
fileName: file.name,
fileSize: this.formatFileSize(file.size),
fileType: file.type
});
try {
// TODO: Implement actual file upload
// const response = await this.uploadFile(file);
// fileMessage.fileUrl = response.url;
// Simulate file upload
setTimeout(() => {
fileMessage.fileUrl = URL.createObjectURL(file);
fileMessage.status = 'delivered';
}, 1000);
} catch (error) {
console.error('Error uploading file:', error);
fileMessage.status = 'failed';
}
},
async handleVoiceRecord(audioBlob) {
console.log('Processing voice recording');
// Add voice message
const voiceMessage = this.addMessage('', 'user', 'voice', {
audioBlob,
duration: '00:05' // TODO: Calculate actual duration
});
// TODO: Send to speech-to-text service
// const transcription = await this.transcribeAudio(audioBlob);
// this.currentMessage = transcription;
// this.sendMessage();
},
// Search functionality
performSearch() {
if (!this.messageSearch.trim()) {
this.isSearching = false;
this.filteredMessages = [];
return;
}
this.isSearching = true;
const query = this.messageSearch.toLowerCase();
this.filteredMessages = this.allMessages.filter(message =>
message.content &&
message.content.toLowerCase().includes(query)
);
},
clearSearch() {
this.messageSearch = '';
this.isSearching = false;
this.filteredMessages = [];
},
// Event handlers voor specialist events
handleSpecialistComplete(eventData) {
console.log('ChatApp received specialist-complete:', eventData);
// Als er een form_request is, toon deze in de ChatInput component
if (eventData.form_request) {
console.log('Setting form request in ChatInput:', eventData.form_request);
try {
// Converteer de form_request naar het verwachte formaat
const formData = this.convertFormRequest(eventData.form_request);
// Stel het formulier in als currentInputFormData in plaats van als bericht toe te voegen
if (formData && formData.title && formData.fields) {
this.currentInputFormData = formData;
} else {
console.error('Invalid form data after conversion:', formData);
}
} catch (err) {
console.error('Error processing form request:', err);
}
}
},
handleSpecialistError(eventData) {
console.log('ChatApp received specialist-error:', eventData);
// Voeg foutbericht toe
this.addMessage(
eventData.message || 'Er is een fout opgetreden bij het verwerken van uw verzoek.',
'ai',
'error'
);
},
// Helper methode om form_request te converteren naar het verwachte formaat
convertFormRequest(formRequest) {
console.log('Converting form request:', formRequest);
if (!formRequest) {
console.error('Geen geldig formRequest ontvangen');
return null;
}
// Controleer of fields een object is voordat we converteren
let fieldsArray;
if (formRequest.fields && typeof formRequest.fields === 'object' && !Array.isArray(formRequest.fields)) {
// Converteer de fields van object naar array formaat
fieldsArray = Object.entries(formRequest.fields).map(([fieldId, fieldDef]) => ({
id: fieldId,
name: fieldDef.name || fieldId, // Gebruik fieldId als fallback
type: fieldDef.type || 'text', // Standaard naar text
description: fieldDef.description || '',
required: fieldDef.required || false,
default: fieldDef.default || '',
allowedValues: fieldDef.allowed_values || null,
context: fieldDef.context || null
}));
} else if (Array.isArray(formRequest.fields)) {
// Als het al een array is, zorg dat alle velden correct zijn
fieldsArray = formRequest.fields.map(field => ({
id: field.id || field.name,
name: field.name || field.id,
type: field.type || 'text',
description: field.description || '',
required: field.required || false,
default: field.default || field.defaultValue || '',
allowedValues: field.allowed_values || field.allowedValues || null,
context: field.context || null
}));
} else {
// Fallback naar lege array als er geen velden zijn
console.warn('Formulier heeft geen geldige velden');
fieldsArray = [];
}
return {
title: formRequest.name || formRequest.title || 'Formulier',
description: formRequest.description || '',
icon: formRequest.icon || 'form',
version: formRequest.version || '1.0',
fields: fieldsArray
};
},
// Event handlers
handleResize() {
this.isMobile = window.innerWidth <= 768;
this.showSidebar = window.innerWidth > 768;
},
handleGlobalKeydown(event) {
// Ctrl/Cmd + K for search
if ((event.ctrlKey || event.metaKey) && event.key === 'k') {
event.preventDefault();
this.focusSearch();
}
// Escape to clear search
if (event.key === 'Escape' && this.isSearching) {
this.clearSearch();
}
},
// Utility methods
async callAPI(endpoint, data) {
// Gebruik de API prefix uit de lokale variabele
const fullEndpoint = this.apiPrefix + '/chat' + endpoint;
console.log('Calling API with prefix:', {
prefix: this.apiPrefix,
endpoint: endpoint,
fullEndpoint: fullEndpoint
});
const response = await fetch(fullEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
},
formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
},
focusSearch() {
this.$refs.searchInput?.focus();
},
renderComponent() {
console.log('🔍 [DEBUG] ChatApp.renderComponent() aangeroepen');
console.log('🔍 [DEBUG] window.Vue beschikbaar:', !!window.Vue);
if (window.Vue) {
console.log('🔍 [DEBUG] window.Vue.createApp beschikbaar:', !!window.Vue.createApp);
console.log('🔍 [DEBUG] window.Vue.version:', window.Vue.version);
}
// We gaan direct de container manipuleren
const container = document.querySelector('.chat-container');
if (!container) {
console.error('Container niet gevonden voor ChatApp (.chat-container)');
return;
}
console.log('🔍 [DEBUG] ChatApp container gevonden, inhoud wordt gerenderd');
console.log('🔍 [DEBUG] Beschikbare components:', {
MessageHistory: !!window.Components?.MessageHistory,
ChatInput: !!window.Components?.ChatInput
});
// Basis layout voor de chat app
container.innerHTML = `
<div class="chat-app-container">
<!-- Message History - takes available space -->
<div id="chat-message-history" class="chat-messages-area"></div>
<!-- Chat Input - to the bottom -->
<div id="chat-input-container" class="chat-input-area"></div>
</div>
`;
// Nu we de DOM structuur hebben, gaan we de componenten initialiseren
const messageHistoryContainer = document.getElementById('chat-message-history');
const chatInputContainer = document.getElementById('chat-input-container');
// Instantieer MessageHistory component met Vue
if (messageHistoryContainer) {
console.log('🔍 [DEBUG] MessageHistory container gevonden, initialiseren...');
try {
// Maak props voor de MessageHistory component
const messageHistoryProps = {
messages: this.allMessages,
isTyping: this.isTyping,
isSubmittingForm: this.isSubmittingForm,
apiPrefix: this.apiPrefix,
autoScroll: true
};
// Maak een nieuwe Vue app en registreer alle componenten
const messageHistoryApp = window.Vue.createApp(MessageHistory, messageHistoryProps);
// Registreer benodigde componenten voor MessageHistory
messageHistoryApp.component('chat-message', ChatMessage);
messageHistoryApp.component('typing-indicator', TypingIndicator);
messageHistoryApp.component('progress-tracker', ProgressTracker);
messageHistoryApp.component('dynamic-form', DynamicForm);
// Error handler
messageHistoryApp.config.errorHandler = (err, vm, info) => {
console.error('🚨 [Vue Error in MessageHistory]', err);
console.error('Component:', vm);
console.error('Error Info:', info);
};
// Geef events door naar de ChatApp
messageHistoryApp.config.globalProperties.$emit = (event, ...args) => {
if (event === 'specialist-complete') {
this.handleSpecialistComplete(args[0]);
} else if (event === 'specialist-error') {
this.handleSpecialistError(args[0]);
}
};
// Mount de component en bewaar de referentie - controleer of renderComponent bestaat
let messageHistoryInstance = null;
if (typeof MessageHistory.renderComponent === 'function') {
messageHistoryInstance = MessageHistory.renderComponent(
messageHistoryContainer,
messageHistoryProps,
messageHistoryApp
);
} else {
// Fallback: direct mounten
messageHistoryInstance = messageHistoryApp.mount(messageHistoryContainer);
console.log('🔍 [DEBUG] MessageHistory direct gemount via app.mount()');
}
// Bewaar de instantie voor toekomstige updates
this.$refs.messageHistory = messageHistoryInstance;
console.log('🔍 [DEBUG] MessageHistory component succesvol geïnitialiseerd');
} catch (error) {
console.error('🚨 [ERROR] Fout bij initialiseren MessageHistory:', error);
}
} else {
console.error('MessageHistory container niet gevonden in de DOM');
}
// Instantieer ChatInput component met Vue
if (chatInputContainer) {
console.log('🔍 [DEBUG] ChatInput container gevonden, initialiseren...');
try {
// Maak props voor de ChatInput component
const chatInputProps = {
currentMessage: this.currentMessage,
isLoading: this.isLoading,
maxLength: this.settings.maxMessageLength,
formData: this.currentInputFormData,
allowFileUpload: this.settings.allowFileUpload,
allowVoiceMessage: this.settings.allowVoiceMessage
};
// Maak een nieuwe Vue app en registreer alle componenten
const chatInputApp = window.Vue.createApp(ChatInput, chatInputProps);
// Registreer benodigde componenten voor ChatInput
chatInputApp.component('dynamic-form', DynamicForm);
chatInputApp.component('form-field', FormField);
// Error handler
chatInputApp.config.errorHandler = (err, vm, info) => {
console.error('🚨 [Vue Error in ChatInput]', err);
console.error('Component:', vm);
console.error('Error Info:', info);
};
// Geef events door naar de ChatApp
chatInputApp.config.globalProperties.$emit = (event, ...args) => {
if (event === 'send-message') {
this.sendMessage();
} else if (event === 'update-message') {
this.updateCurrentMessage(args[0]);
} else if (event === 'submit-form') {
this.submitFormFromInput(args[0]);
} else if (event === 'upload-file') {
this.handleFileUpload(args[0]);
} else if (event === 'record-voice') {
this.handleVoiceRecord(args[0]);
}
};
// Mount de component en bewaar de referentie - controleer of renderComponent bestaat
let chatInputInstance = null;
if (typeof ChatInput.renderComponent === 'function') {
console.log('🔍 [DEBUG] ChatInput.renderComponent wordt aangeroepen met chatInputApp:', chatInputApp);
console.log('🔍 [DEBUG] chatInputApp.mount type:', typeof chatInputApp.mount);
chatInputInstance = ChatInput.renderComponent(
chatInputContainer,
chatInputProps,
chatInputApp
);
} else {
// Fallback: direct mounten
console.log('🔍 [DEBUG] ChatInput wordt direct gemount via app.mount()');
chatInputInstance = chatInputApp.mount(chatInputContainer);
console.log('🔍 [DEBUG] ChatInput direct gemount via app.mount()');
}
// Bewaar de instantie voor toekomstige updates
this.$refs.chatInput = chatInputInstance;
console.log('🔍 [DEBUG] ChatInput component succesvol geïnitialiseerd');
} catch (error) {
console.error('🚨 [ERROR] Fout bij initialiseren ChatInput:', error);
}
} else {
console.error('ChatInput container niet gevonden in de DOM');
}
console.log('🔍 [DEBUG] ChatApp succesvol gerenderd met alle componenten');
},
},
// Voeg een minimale render functie toe (vergelijkbaar met LanguageSelector)
render() {
return document.createElement('div');
},
template: `
<div class="chat-app-container">
<!-- Message History - takes available space -->
<message-history
:messages="displayMessages"
:is-typing="isTyping"
:is-submitting-form="isSubmittingForm"
:api-prefix="apiPrefix"
:auto-scroll="true"
@specialist-error="handleSpecialistError"
@specialist-complete="handleSpecialistComplete"
ref="messageHistory"
class="chat-messages-area"
></message-history>
<!-- Chat Input - to the bottom -->
<chat-input
:current-message="currentMessage"
:is-loading="isLoading"
:max-length="2000"
:allow-file-upload="true"
:allow-voice-message="false"
:form-data="currentInputFormData"
@send-message="sendMessage"
@update-message="updateCurrentMessage"
@upload-file="handleFileUpload"
@record-voice="handleVoiceRecord"
@submit-form="submitFormFromInput"
ref="chatInput"
class="chat-input-area"
></chat-input>
</div>
`
};