tussentijdse status voor significante wijzigingen. Bezig aan creatie Dynamic Form in de chat client.

This commit is contained in:
Josako
2025-06-13 14:19:05 +02:00
parent b326c0c6f2
commit f1c60f9574
17 changed files with 1012 additions and 255 deletions

View File

@@ -5,64 +5,173 @@ export const DynamicForm = {
type: Object,
required: true,
validator: (formData) => {
return formData.title && formData.fields && Array.isArray(formData.fields);
return formData && formData.title && formData.fields &&
(Array.isArray(formData.fields) || typeof formData.fields === 'object');
}
},
formValues: {
type: Object,
required: true
default: () => ({})
},
isSubmitting: {
type: Boolean,
default: false
},
readOnly: {
type: Boolean,
default: false
},
hideActions: {
type: Boolean,
default: false
}
},
emits: ['submit', 'cancel', 'update:formValues'],
data() {
return {
localFormValues: { ...this.formValues }
};
},
watch: {
formValues: {
handler(newValues) {
this.localFormValues = { ...newValues };
},
deep: true
},
localFormValues: {
handler(newValues) {
this.$emit('update:formValues', newValues);
},
deep: true
}
},
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());
});
const missingFields = [];
if (Array.isArray(this.formData.fields)) {
// Valideer array-gebaseerde velden
this.formData.fields.forEach(field => {
const fieldId = field.id || field.name;
if (field.required) {
const value = this.localFormValues[fieldId];
if (value === undefined || value === null ||
(typeof value === 'string' && !value.trim()) ||
(Array.isArray(value) && value.length === 0)) {
missingFields.push(field.name);
}
}
});
} else {
// Valideer object-gebaseerde velden
Object.entries(this.formData.fields).forEach(([fieldId, field]) => {
if (field.required) {
const value = this.localFormValues[fieldId];
if (value === undefined || value === null ||
(typeof value === 'string' && !value.trim()) ||
(Array.isArray(value) && value.length === 0)) {
missingFields.push(field.name);
}
}
});
};
if (missingFields.length > 0) {
const fieldNames = missingFields.map(f => f.label).join(', ');
const fieldNames = missingFields.join(', ');
alert(`De volgende velden zijn verplicht: ${fieldNames}`);
return;
}
this.$emit('submit');
this.$emit('submit', this.localFormValues);
},
handleCancel() {
this.$emit('cancel');
},
updateFieldValue(fieldName, value) {
// Emit an update for reactive binding
this.$emit('update-field', fieldName, value);
updateFieldValue(fieldId, value) {
this.localFormValues[fieldId] = value;
}
},
template: `
<div class="dynamic-form">
<div class="form-title">{{ formData.title }}</div>
<div v-if="formData.description" class="form-description">
{{ formData.description }}
<div class="dynamic-form" :class="{ 'read-only': readOnly }">
<div class="form-header" v-if="formData.title || formData.icon">
<div class="form-icon" v-if="formData.icon">
<i class="material-icons">{{ formData.icon }}</i>
</div>
<div class="form-title">{{ formData.title }}</div>
</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">
<div v-if="readOnly" class="form-readonly">
<!-- Array-based fields -->
<template v-if="Array.isArray(formData.fields)">
<div v-for="field in formData.fields" :key="field.id || field.name" class="form-field-readonly">
<div class="field-label">{{ field.name }}:</div>
<div class="field-value">
<template v-if="field.type === 'enum' && (field.allowedValues || field.allowed_values)">
{{ localFormValues[field.id || field.name] || field.default || '-' }}
</template>
<template v-else-if="field.type === 'boolean'">
{{ localFormValues[field.id || field.name] ? 'Ja' : 'Nee' }}
</template>
<template v-else-if="field.type === 'text'">
<div class="text-value">{{ localFormValues[field.id || field.name] || '-' }}</div>
</template>
<template v-else>
{{ localFormValues[field.id || field.name] || field.default || '-' }}
</template>
</div>
</div>
</template>
<!-- Object-based fields -->
<template v-else>
<div v-for="(field, fieldId) in formData.fields" :key="fieldId" class="form-field-readonly">
<div class="field-label">{{ field.name }}:</div>
<div class="field-value">
<template v-if="field.type === 'enum' && (field.allowedValues || field.allowed_values)">
{{ localFormValues[fieldId] || field.default || '-' }}
</template>
<template v-else-if="field.type === 'boolean'">
{{ localFormValues[fieldId] ? 'Ja' : 'Nee' }}
</template>
<template v-else-if="field.type === 'text'">
<div class="text-value">{{ localFormValues[fieldId] || '-' }}</div>
</template>
<template v-else>
{{ localFormValues[fieldId] || field.default || '-' }}
</template>
</div>
</div>
</template>
</div>
<form v-else @submit.prevent="handleSubmit" novalidate>
<div class="form-fields">
<template v-if="Array.isArray(formData.fields)">
<form-field
v-for="field in formData.fields"
:key="field.id || field.name"
:field-id="field.id || field.name"
:field="field"
:model-value="localFormValues[field.id || field.name]"
@update:model-value="localFormValues[field.id || field.name] = $event"
></form-field>
</template>
<template v-else>
<form-field
v-for="(field, fieldId) in formData.fields"
:key="fieldId"
:field-id="fieldId"
:field="field"
:model-value="localFormValues[fieldId]"
@update:model-value="localFormValues[fieldId] = $event"
></form-field>
</template>
</div>
<div class="form-actions" v-if="!hideActions">
<button
type="submit"
class="btn btn-primary"
@@ -72,7 +181,7 @@ export const DynamicForm = {
<span v-if="isSubmitting" class="spinner"></span>
{{ isSubmitting ? 'Verzenden...' : (formData.submitText || 'Versturen') }}
</button>
<button
type="button"
class="btn btn-secondary"
@@ -81,28 +190,6 @@ export const DynamicForm = {
>
{{ 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>