Files
eveAI/eveai_chat_client/static/assets/js/components/MessageHistory.js

230 lines
8.3 KiB
JavaScript

// Import afhankelijke componenten
import { ChatMessage } from './ChatMessage.js';
import { TypingIndicator } from './TypingIndicator.js';
import { ProgressTracker } from './ProgressTracker.js';
export const MessageHistory = {
name: 'MessageHistory',
components: {
'chat-message': ChatMessage,
'typing-indicator': TypingIndicator,
'progress-tracker': ProgressTracker
},
props: {
messages: {
type: Array,
required: true,
default: () => []
},
isTyping: {
type: Boolean,
default: false
},
isSubmittingForm: {
type: Boolean,
default: false
},
apiPrefix: {
type: String,
default: ''
},
autoScroll: {
type: Boolean,
default: true
}
},
emits: ['submit-form', 'load-more', 'specialist-complete', 'specialist-error'],
data() {
return {
isAtBottom: true,
unreadCount: 0,
originalFirstMessage: null,
isTranslating: false, // Vlag om dubbele vertaling te voorkomen
languageChangeHandler: null // Referentie voor cleanup
};
},
mounted() {
this.scrollToBottom();
this.setupScrollListener();
this.listenForLanguageChanges();
// Sla de originele inhoud van het eerste bericht op als er maar één bericht is
if (this.messages.length === 1 && this.messages[0].sender === 'ai') {
this.originalFirstMessage = this.messages[0].content;
}
},
updated() {
if (this.autoScroll && this.isAtBottom) {
this.$nextTick(() => this.scrollToBottom());
}
},
methods: {
listenForLanguageChanges() {
// Maak een benoemde handler voor cleanup
this.languageChangeHandler = (event) => {
if (event.detail && event.detail.language) {
this.translateFirstMessageIfNeeded(event.detail.language);
}
};
document.addEventListener('language-changed', this.languageChangeHandler);
},
async translateFirstMessageIfNeeded(language) {
// Voorkom dubbele vertaling
if (this.isTranslating) {
console.log('Vertaling al bezig, overslaan...');
return;
}
// Alleen vertalen als er precies één bericht is en het is van de AI
if (this.messages.length === 1 && this.messages[0].sender === 'ai') {
const firstMessage = this.messages[0];
// Controleer of we een origineel bericht hebben om te vertalen
const contentToTranslate = this.originalFirstMessage || firstMessage.content;
// Sla het originele bericht op als we dat nog niet hebben gedaan
if (!this.originalFirstMessage) {
this.originalFirstMessage = contentToTranslate;
}
// Zet de vertaling vlag
this.isTranslating = true;
try {
// Controleer of de vertaalclient beschikbaar is
if (!window.TranslationClient || typeof window.TranslationClient.translate !== 'function') {
console.error('TranslationClient.translate is niet beschikbaar');
return;
}
console.log(`Vertalen van eerste bericht naar ${language}`);
// Vertaal het bericht met de juiste context
const response = await window.TranslationClient.translate(
contentToTranslate,
language,
null, // source_lang (auto-detect)
'first_message', // context
this.apiPrefix // API prefix voor tenant routing
);
if (response.success) {
console.log('Vertaling van eerste bericht voltooid:', response.translated_text);
// Update het bericht zonder een indicator te tonen
firstMessage.content = response.translated_text;
} else {
console.error('Vertaling van eerste bericht mislukt:', response.error);
}
} catch (error) {
console.error('Fout bij het vertalen van eerste bericht:', error);
} finally {
// Reset de vertaling vlag
this.isTranslating = false;
}
}
},
scrollToBottom() {
const container = this.$refs.messagesContainer;
if (container) {
container.scrollTop = container.scrollHeight;
this.isAtBottom = true;
this.showScrollButton = false;
this.unreadCount = 0;
}
},
setupScrollListener() {
const container = this.$refs.messagesContainer;
if (!container) return;
container.addEventListener('scroll', this.handleScroll);
},
handleScroll() {
const container = this.$refs.messagesContainer;
if (!container) return;
const threshold = 100; // pixels from bottom
const isNearBottom = container.scrollHeight - container.scrollTop - container.clientHeight < threshold;
this.isAtBottom = isNearBottom;
// Load more messages when scrolled to top
if (container.scrollTop === 0) {
this.$emit('load-more');
}
},
handleImageLoaded() {
// Auto-scroll when images load to maintain position
if (this.isAtBottom) {
this.$nextTick(() => this.scrollToBottom());
}
},
searchMessages(query) {
// Simple message search
if (!query.trim()) return this.messages;
const searchTerm = query.toLowerCase();
return this.messages.filter(message =>
message.content &&
message.content.toLowerCase().includes(searchTerm)
);
},
},
beforeUnmount() {
// Cleanup scroll listener
const container = this.$refs.messagesContainer;
if (container) {
container.removeEventListener('scroll', this.handleScroll);
}
// Cleanup language change listener
if (this.languageChangeHandler) {
document.removeEventListener('language-changed', this.languageChangeHandler);
}
},
template: `
<div class="message-history-container">
<!-- Messages container -->
<div class="chat-messages" ref="messagesContainer">
<!-- Loading indicator for load more -->
<div v-if="$slots.loading" class="load-more-indicator">
<slot name="loading"></slot>
</div>
<!-- Empty state -->
<div v-if="messages.length === 0" class="empty-state">
<div class="empty-icon">💬</div>
<div class="empty-text">Nog geen berichten</div>
<div class="empty-subtext">Start een gesprek door een bericht te typen!</div>
</div>
<!-- Message list -->
<template v-else>
<!-- Messages -->
<template v-for="(message, index) in messages" :key="message.id">
<!-- The actual message -->
<chat-message
:message="message"
:is-submitting-form="isSubmittingForm"
:api-prefix="apiPrefix"
@image-loaded="handleImageLoaded"
@specialist-complete="$emit('specialist-complete', $event)"
@specialist-error="$emit('specialist-error', $event)"
></chat-message>
</template>
</template>
<!-- Typing indicator -->
<typing-indicator v-if="isTyping"></typing-indicator>
</div>
</div>
`
};