- introductie van vue files - bijna werkende versie van eveai_chat_client.
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
<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>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ChatMessage from './ChatMessage.vue';
|
||||
import TypingIndicator from './TypingIndicator.vue';
|
||||
|
||||
export default {
|
||||
name: 'MessageHistory',
|
||||
components: {
|
||||
'chat-message': ChatMessage,
|
||||
'typing-indicator': TypingIndicator
|
||||
},
|
||||
props: {
|
||||
messages: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
isTyping: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isSubmittingForm: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
apiPrefix: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
autoScroll: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
emits: ['load-more', 'specialist-complete', 'specialist-error'],
|
||||
data() {
|
||||
return {
|
||||
isAtBottom: true,
|
||||
showScrollButton: false,
|
||||
unreadCount: 0,
|
||||
languageChangeHandler: null
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
messages: {
|
||||
handler(newMessages, oldMessages) {
|
||||
// Auto-scroll when new messages are added
|
||||
if (this.autoScroll && newMessages.length > (oldMessages?.length || 0)) {
|
||||
this.$nextTick(() => {
|
||||
this.scrollToBottom();
|
||||
});
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
isTyping(newVal) {
|
||||
if (newVal && this.autoScroll) {
|
||||
this.$nextTick(() => {
|
||||
this.scrollToBottom();
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// Maak een benoemde handler voor betere cleanup
|
||||
this.languageChangeHandler = (event) => {
|
||||
if (event.detail && event.detail.language) {
|
||||
this.handleLanguageChange(event);
|
||||
}
|
||||
};
|
||||
|
||||
// Luister naar taalwijzigingen
|
||||
document.addEventListener('language-changed', this.languageChangeHandler);
|
||||
},
|
||||
mounted() {
|
||||
this.setupScrollListener();
|
||||
|
||||
// Initial scroll to bottom
|
||||
if (this.autoScroll) {
|
||||
this.$nextTick(() => {
|
||||
this.scrollToBottom();
|
||||
});
|
||||
}
|
||||
},
|
||||
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);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async handleLanguageChange(event) {
|
||||
// Controleer of dit het eerste bericht is in een gesprek met maar één bericht
|
||||
if (this.messages.length === 1 && this.messages[0].sender === 'ai') {
|
||||
const firstMessage = this.messages[0];
|
||||
|
||||
// Controleer of we een originele inhoud hebben om te vertalen
|
||||
if (firstMessage.originalContent) {
|
||||
console.log('Vertaling van eerste AI bericht naar:', event.detail.language);
|
||||
|
||||
try {
|
||||
// Controleer of TranslationClient beschikbaar is
|
||||
if (!window.TranslationClient || typeof window.TranslationClient.translate !== 'function') {
|
||||
console.error('TranslationClient.translate is niet beschikbaar');
|
||||
return;
|
||||
}
|
||||
|
||||
// Gebruik TranslationClient
|
||||
const response = await window.TranslationClient.translate(
|
||||
firstMessage.originalContent,
|
||||
event.detail.language,
|
||||
null, // source_lang (auto-detect)
|
||||
'chat_message', // context
|
||||
this.apiPrefix // API prefix voor tenant routing
|
||||
);
|
||||
|
||||
if (response.success) {
|
||||
// Update de inhoud van het bericht
|
||||
firstMessage.content = response.translated_text;
|
||||
console.log('Eerste bericht succesvol vertaald');
|
||||
} else {
|
||||
console.error('Vertaling mislukt:', response.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fout bij vertalen eerste bericht:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.message-history-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
.load-more-indicator {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 16px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.empty-subtext {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
max-width: 300px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Scrollbar styling */
|
||||
.chat-messages::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.chat-messages::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.chat-messages::-webkit-scrollbar-thumb {
|
||||
background: #c1c1c1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.chat-messages::-webkit-scrollbar-thumb:hover {
|
||||
background: #a8a8a8;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.chat-messages {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 20px 16px;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user