251 lines
8.2 KiB
JavaScript
251 lines
8.2 KiB
JavaScript
// static/js/components/ChatInput.js
|
|
|
|
export const ChatInput = {
|
|
name: 'ChatInput',
|
|
components: {
|
|
'dynamic-form': window.__vueApp ? DynamicForm : null
|
|
},
|
|
props: {
|
|
currentMessage: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
isLoading: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
placeholder: {
|
|
type: String,
|
|
default: 'Typ je bericht hier... (Enter om te verzenden, Shift+Enter voor nieuwe regel)'
|
|
},
|
|
maxLength: {
|
|
type: Number,
|
|
default: 2000
|
|
},
|
|
formData: {
|
|
type: Object,
|
|
default: null
|
|
},
|
|
},
|
|
emits: ['send-message', 'update-message', 'submit-form'],
|
|
watch: {
|
|
formData: {
|
|
handler(newFormData) {
|
|
console.log('ChatInput received formData:', newFormData);
|
|
if (newFormData) {
|
|
this.formValues = {}; // Reset formulierwaarden
|
|
this.showForm = true;
|
|
} else {
|
|
this.showForm = false;
|
|
}
|
|
},
|
|
immediate: true
|
|
},
|
|
currentMessage(newVal) {
|
|
this.localMessage = newVal;
|
|
},
|
|
localMessage(newVal) {
|
|
this.$emit('update-message', newVal);
|
|
this.autoResize();
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
localMessage: this.currentMessage,
|
|
formValues: {},
|
|
showForm: false
|
|
};
|
|
},
|
|
computed: {
|
|
characterCount() {
|
|
return this.localMessage.length;
|
|
},
|
|
|
|
isOverLimit() {
|
|
return this.characterCount > this.maxLength;
|
|
},
|
|
|
|
hasFormData() {
|
|
return this.formData && this.formData.fields &&
|
|
((Array.isArray(this.formData.fields) && this.formData.fields.length > 0) ||
|
|
(typeof this.formData.fields === 'object' && Object.keys(this.formData.fields).length > 0));
|
|
},
|
|
|
|
canSend() {
|
|
const hasValidForm = this.showForm && this.formData && this.validateForm();
|
|
const hasValidMessage = this.localMessage.trim() && !this.isOverLimit;
|
|
|
|
return (!this.isLoading) && (hasValidForm || hasValidMessage);
|
|
},
|
|
|
|
sendButtonText() {
|
|
return this.showForm ? 'Verstuur formulier' : 'Verstuur bericht';
|
|
}
|
|
},
|
|
mounted() {
|
|
this.autoResize();
|
|
},
|
|
methods: {
|
|
handleKeydown(event) {
|
|
if (event.key === 'Enter' && !event.shiftKey) {
|
|
event.preventDefault();
|
|
this.sendMessage();
|
|
} else if (event.key === 'Escape') {
|
|
this.localMessage = '';
|
|
}
|
|
},
|
|
|
|
sendMessage() {
|
|
if (!this.canSend) return;
|
|
|
|
if (this.showForm && this.formData) {
|
|
// Valideer het formulier
|
|
if (this.validateForm()) {
|
|
// Verstuur het formulier
|
|
this.$emit('submit-form', this.formValues);
|
|
this.formValues = {};
|
|
// Reset het formulier na verzenden
|
|
this.showForm = false;
|
|
}
|
|
} else if (this.localMessage.trim()) {
|
|
// Verstuur normaal bericht
|
|
this.$emit('send-message');
|
|
}
|
|
},
|
|
|
|
validateForm() {
|
|
if (!this.formData || !this.formData.fields) return false;
|
|
|
|
// Controleer of alle verplichte velden zijn ingevuld
|
|
let missingFields = [];
|
|
|
|
if (Array.isArray(this.formData.fields)) {
|
|
missingFields = this.formData.fields.filter(field => {
|
|
if (!field.required) return false;
|
|
const fieldId = field.id || field.name;
|
|
const value = this.formValues[fieldId];
|
|
return value === undefined || value === null || (typeof value === 'string' && !value.trim());
|
|
});
|
|
} else {
|
|
// Voor object-gebaseerde velden
|
|
Object.entries(this.formData.fields).forEach(([fieldId, field]) => {
|
|
if (field.required) {
|
|
const value = this.formValues[fieldId];
|
|
if (value === undefined || value === null || (typeof value === 'string' && !value.trim())) {
|
|
missingFields.push(field);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
return missingFields.length === 0;
|
|
},
|
|
|
|
autoResize() {
|
|
this.$nextTick(() => {
|
|
const textarea = this.$refs.messageInput;
|
|
if (textarea) {
|
|
textarea.style.height = 'auto';
|
|
textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px';
|
|
}
|
|
});
|
|
},
|
|
|
|
focusInput() {
|
|
this.$refs.messageInput?.focus();
|
|
},
|
|
|
|
clearInput() {
|
|
this.localMessage = '';
|
|
this.focusInput();
|
|
},
|
|
|
|
toggleForm() {
|
|
this.showForm = !this.showForm;
|
|
if (!this.showForm) {
|
|
this.focusInput();
|
|
}
|
|
},
|
|
|
|
submitForm() {
|
|
if (this.canSubmitForm) {
|
|
this.$emit('submit-form', { ...this.formValues });
|
|
this.showForm = false;
|
|
this.focusInput();
|
|
}
|
|
},
|
|
|
|
cancelForm() {
|
|
this.showForm = false;
|
|
this.focusInput();
|
|
},
|
|
|
|
updateFormValues(newValues) {
|
|
this.formValues = { ...newValues };
|
|
}
|
|
},
|
|
template: `
|
|
<div class="chat-input-container">
|
|
<div v-if="formData && showForm" class="dynamic-form-container">
|
|
<dynamic-form
|
|
:form-data="formData"
|
|
:form-values="formValues"
|
|
:is-submitting="isLoading"
|
|
:hide-actions="true"
|
|
@update:form-values="updateFormValues"
|
|
></dynamic-form>
|
|
</div>
|
|
|
|
<div class="chat-input">
|
|
<!-- Main input area -->
|
|
<div class="input-main">
|
|
<textarea
|
|
ref="messageInput"
|
|
v-model="localMessage"
|
|
@keydown="handleKeydown"
|
|
:placeholder="placeholder"
|
|
rows="1"
|
|
:disabled="isLoading"
|
|
:maxlength="maxLength"
|
|
class="message-input"
|
|
:class="{ 'over-limit': isOverLimit }"
|
|
></textarea>
|
|
|
|
<!-- Character counter -->
|
|
<div v-if="maxLength" class="character-counter" :class="{ 'over-limit': isOverLimit }">
|
|
{{ characterCount }}/{{ maxLength }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Input actions -->
|
|
<div class="input-actions">
|
|
<!-- Formulier toggle knop -->
|
|
<button
|
|
v-if="hasFormData"
|
|
@click="toggleForm"
|
|
class="form-toggle-btn"
|
|
:disabled="isLoading"
|
|
:class="{ 'active': showForm }"
|
|
:title="showForm ? 'Verberg formulier' : 'Toon formulier'"
|
|
>
|
|
<i class="material-icons">description</i>
|
|
</button>
|
|
|
|
<!-- Send button -->
|
|
<button
|
|
@click="sendMessage"
|
|
class="send-btn"
|
|
:class="{ 'form-mode': showForm && formData }"
|
|
:disabled="!canSend"
|
|
:title="showForm ? 'Verstuur formulier' : 'Verstuur bericht'"
|
|
>
|
|
<span v-if="isLoading" class="loading-spinner">⏳</span>
|
|
<svg v-else width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`
|
|
}; |