Add LogicConfirmationModal Component and Integrate Logic Validation (#742)
* Add LogicConfirmationModal Component and Integrate Logic Validation - Introduced LogicConfirmationModal component to display validation errors related to form logic. - Integrated logic validation and cleaning functionalities into FormEditor, prompting users when invalid logic is detected. - Added useLogicValidation and useLogicCleaner composables for error checking and logic correction. - Removed deprecated validatePropertiesLogic function to streamline logic handling. These changes enhance user experience by providing clear feedback on form logic issues and ensuring that invalid logic is addressed before form submission. * Refactor Logic Handling in Form Components - Updated LogicConfirmationModal to improve user feedback by changing the title and icon colors, enhancing clarity on incomplete form logic. - Replaced useLogicValidation and useLogicCleaner with a new useFormLogic composable in FormEditor for streamlined logic validation and cleaning processes. - Removed deprecated useLogicCleaner and useLogicValidation files to simplify the codebase and improve maintainability. These changes enhance the user experience by providing clearer messages regarding form logic issues and ensuring that invalid logic is effectively managed before form submission. --------- Co-authored-by: JhumanJ <julien@nahum.net>
This commit is contained in:
103
client/components/forms/LogicConfirmationModal.vue
Normal file
103
client/components/forms/LogicConfirmationModal.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<Modal
|
||||
:show="isVisible"
|
||||
compact-header
|
||||
icon-color="yellow"
|
||||
@close="$emit('cancel')"
|
||||
>
|
||||
<template #title>
|
||||
Incomplete Form Logic
|
||||
</template>
|
||||
<template #icon>
|
||||
<Icon
|
||||
name="heroicons:exclamation-triangle"
|
||||
class="h-7 w-7"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<p class=" text-gray-700">
|
||||
Some logic rules are incomplete or invalid and will be cleaned up to ensure that the form works correctly.
|
||||
</p>
|
||||
|
||||
<div class="mt-4 space-y-3">
|
||||
<template
|
||||
v-for="error in groupedErrors"
|
||||
:key="error.fieldId"
|
||||
>
|
||||
<div class="rounded-lg bg-yellow-50 p-3">
|
||||
<div class="flex items-center">
|
||||
<Icon
|
||||
name="heroicons:exclamation-triangle"
|
||||
class="h-5 w-5 text-yellow-400"
|
||||
/>
|
||||
<h4 class="ml-2 text-sm font-medium text-yellow-800">
|
||||
Field: {{ error.fieldName }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="mt-2 text-sm text-yellow-700">
|
||||
<ul class="list-disc pl-5 space-y-1">
|
||||
<li
|
||||
v-for="(message, index) in error.messages"
|
||||
:key="index"
|
||||
>
|
||||
{{ message }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex justify-end space-x-3">
|
||||
<UButton
|
||||
variant="outline"
|
||||
@click="$emit('cancel')"
|
||||
>
|
||||
Cancel
|
||||
</UButton>
|
||||
<UButton
|
||||
color="blue"
|
||||
@click="$emit('confirm')"
|
||||
>
|
||||
Save Anyway (Remove Invalid Logic)
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
isVisible: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
errors: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
defineEmits(['cancel', 'confirm'])
|
||||
|
||||
// Group errors by field and format messages
|
||||
const groupedErrors = computed(() => {
|
||||
const errorMap = new Map()
|
||||
|
||||
props.errors.forEach(error => {
|
||||
if (!errorMap.has(error.fieldId)) {
|
||||
errorMap.set(error.fieldId, {
|
||||
fieldId: error.fieldId,
|
||||
fieldName: error.fieldName,
|
||||
messages: []
|
||||
})
|
||||
}
|
||||
|
||||
const group = errorMap.get(error.fieldId)
|
||||
group.messages.push(error.message)
|
||||
})
|
||||
|
||||
return Array.from(errorMap.values())
|
||||
})
|
||||
</script>
|
||||
@@ -84,6 +84,14 @@
|
||||
:validation-error-response="validationErrorResponse"
|
||||
@close="showFormErrorModal = false"
|
||||
/>
|
||||
|
||||
<!-- Logic Confirmation Modal -->
|
||||
<LogicConfirmationModal
|
||||
:is-visible="showLogicConfirmationModal"
|
||||
:errors="logicErrors"
|
||||
@cancel="handleLogicConfirmationCancel"
|
||||
@confirm="handleLogicConfirmationConfirm"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
@@ -100,13 +108,14 @@ import FormErrorModal from "./form-components/FormErrorModal.vue"
|
||||
import FormFieldsEditor from './FormFieldsEditor.vue'
|
||||
import FormCustomization from "./form-components/FormCustomization.vue"
|
||||
import FormEditorPreview from "./form-components/FormEditorPreview.vue"
|
||||
import { validatePropertiesLogic } from "~/composables/forms/validatePropertiesLogic.js"
|
||||
import { useFormLogic } from "~/composables/forms/useFormLogic.js"
|
||||
import opnformConfig from "~/opnform.config.js"
|
||||
import { captureException } from "@sentry/core"
|
||||
import FormSettings from './form-components/FormSettings.vue'
|
||||
import FormEditorErrorHandler from '~/components/open/forms/components/FormEditorErrorHandler.vue'
|
||||
import { setFormDefaults } from '~/composables/forms/initForm.js'
|
||||
import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'
|
||||
import LogicConfirmationModal from '~/components/forms/LogicConfirmationModal.vue'
|
||||
|
||||
export default {
|
||||
name: "FormEditor",
|
||||
@@ -118,7 +127,8 @@ export default {
|
||||
FormCustomization,
|
||||
FormFieldsEditor,
|
||||
FormErrorModal,
|
||||
FormSettings
|
||||
FormSettings,
|
||||
LogicConfirmationModal
|
||||
},
|
||||
props: {
|
||||
isEdit: {
|
||||
@@ -179,9 +189,11 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
showFormErrorModal: false,
|
||||
showLogicConfirmationModal: false,
|
||||
validationErrorResponse: null,
|
||||
updateFormLoading: false,
|
||||
createdFormSlug: null,
|
||||
logicErrors: [],
|
||||
}
|
||||
},
|
||||
|
||||
@@ -238,7 +250,24 @@ export default {
|
||||
const defaultedData = setFormDefaults(this.form.data())
|
||||
this.form.fill(defaultedData)
|
||||
|
||||
this.form.properties = validatePropertiesLogic(this.form.properties)
|
||||
// Check for logic errors
|
||||
const { getLogicErrors } = useFormLogic()
|
||||
this.logicErrors = getLogicErrors(this.form.properties)
|
||||
|
||||
if (this.logicErrors.length > 0) {
|
||||
this.showLogicConfirmationModal = true
|
||||
return
|
||||
}
|
||||
|
||||
this.proceedWithSave()
|
||||
},
|
||||
proceedWithSave() {
|
||||
if (this.logicErrors.length > 0) {
|
||||
// Clean invalid logic before saving using the comprehensive validator
|
||||
const { validatePropertiesLogic } = useFormLogic()
|
||||
this.form.properties = validatePropertiesLogic(this.form.properties)
|
||||
}
|
||||
|
||||
if (this.isGuest) {
|
||||
this.saveFormGuest()
|
||||
} else if (this.isEdit) {
|
||||
@@ -247,6 +276,13 @@ export default {
|
||||
this.saveFormCreate()
|
||||
}
|
||||
},
|
||||
handleLogicConfirmationCancel() {
|
||||
this.showLogicConfirmationModal = false
|
||||
},
|
||||
handleLogicConfirmationConfirm() {
|
||||
this.showLogicConfirmationModal = false
|
||||
this.proceedWithSave()
|
||||
},
|
||||
saveFormEdit() {
|
||||
if (this.updateFormLoading) return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user