- Build of the Chat Client using Vue.js
- Accompanying css - Views to serve the Chat Client - first test version of the TRACIE_SELECTION_SPECIALIST - ESS Implemented.
This commit is contained in:
110
eveai_chat_client/static/js/components/DynamicForm.js
Normal file
110
eveai_chat_client/static/js/components/DynamicForm.js
Normal file
@@ -0,0 +1,110 @@
|
||||
export const DynamicForm = {
|
||||
name: 'DynamicForm',
|
||||
props: {
|
||||
formData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
validator: (formData) => {
|
||||
return formData.title && formData.fields && Array.isArray(formData.fields);
|
||||
}
|
||||
},
|
||||
formValues: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
isSubmitting: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ['submit', 'cancel'],
|
||||
methods: {
|
||||
handleSubmit() {
|
||||
// Basic validation
|
||||
const requiredFields = this.formData.fields.filter(field => field.required);
|
||||
const missingFields = requiredFields.filter(field => {
|
||||
const value = this.formValues[field.name];
|
||||
return !value || (typeof value === 'string' && !value.trim());
|
||||
});
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
const fieldNames = missingFields.map(f => f.label).join(', ');
|
||||
alert(`De volgende velden zijn verplicht: ${fieldNames}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.$emit('submit');
|
||||
},
|
||||
|
||||
handleCancel() {
|
||||
this.$emit('cancel');
|
||||
},
|
||||
|
||||
updateFieldValue(fieldName, value) {
|
||||
// Emit an update for reactive binding
|
||||
this.$emit('update-field', fieldName, value);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="dynamic-form">
|
||||
<div class="form-title">{{ formData.title }}</div>
|
||||
|
||||
<div v-if="formData.description" class="form-description">
|
||||
{{ formData.description }}
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="handleSubmit" novalidate>
|
||||
<form-field
|
||||
v-for="field in formData.fields"
|
||||
:key="field.name"
|
||||
:field="field"
|
||||
:model-value="formValues[field.name]"
|
||||
@update:model-value="formValues[field.name] = $event"
|
||||
></form-field>
|
||||
|
||||
<div class="form-actions">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
:disabled="isSubmitting"
|
||||
:class="{ 'loading': isSubmitting }"
|
||||
>
|
||||
<span v-if="isSubmitting" class="spinner"></span>
|
||||
{{ isSubmitting ? 'Verzenden...' : (formData.submitText || 'Versturen') }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
@click="handleCancel"
|
||||
:disabled="isSubmitting"
|
||||
>
|
||||
{{ formData.cancelText || 'Annuleren' }}
|
||||
</button>
|
||||
|
||||
<!-- Optional reset button -->
|
||||
<button
|
||||
v-if="formData.showReset"
|
||||
type="reset"
|
||||
class="btn btn-outline"
|
||||
@click="$emit('reset')"
|
||||
:disabled="isSubmitting"
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Progress indicator for multi-step forms -->
|
||||
<div v-if="formData.steps && formData.currentStep" class="form-progress">
|
||||
<div class="progress-bar">
|
||||
<div
|
||||
class="progress-fill"
|
||||
:style="{ width: (formData.currentStep / formData.steps * 100) + '%' }"
|
||||
></div>
|
||||
</div>
|
||||
<small>Stap {{ formData.currentStep }} van {{ formData.steps }}</small>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
Reference in New Issue
Block a user